AAYMA
RU
Войти

Контур

Консультант-закупщик по каталогу ekt.kz: чат-подбор товаров, разбор спецификаций (XLSX/DOCX/PDF/JPEG), выявление противоречий в карточках и…

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

О проекте

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

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

Суть

Консультант-закупщик по каталогу ekt.kz: чат-подбор товаров, разбор спецификаций (XLSX/DOCX/PDF/JPEG), выявление противоречий в карточках и серверная корзина с подтверждением конкретного предложения.

Как устроено

FastAPI + SQLite хранят каталог-снимок (10 карточек ekt.kz + 3 учебные позиции), сессии, документы, предложения и корзины. LLM-слой (fixtures / OpenAI gpt-4.1-mini structured outputs / fallback на правила) разбирает запросы и OCR JPEG, а допустимость покупки, цены и суммы определяют серверные правила. При конфликте полей (описание 160 А против свойства 250 А) предложение блокируется до правки строки; подтверждается ID предложения с повторной проверкой цены и наличия. Фронт React+Vite+Tailwind.

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

  • structured outputs
  • OCR via OpenAI vision
  • field conflict detection
  • rule-based fallback
  • idempotent confirmed cart
  • demo fixtures

Особенности

Проверка противоречий между описанием и свойствами товара с блокировкой предложения; работает полностью без ключей в DEMO_MODE на записанных ответах; видео-демо с субтитрами и презентация в репозитории.

Стек

Python · FastAPI · Pydantic · SQLite · uv · React · TypeScript · Vite · Tailwind · Docker Compose

Модели

gpt-4.1-mini


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

README

README.md

Контур — проверяемая закупка электротоваров

От запроса или спецификации — к корзине, состав которой проверил человек. Контур помогает закупщику найти товар ekt.kz, сопоставить характеристики и наличие на складе, заметить противоречия и подтвердить покупаемое количество.

Демонстрация работает без API-ключей: 13 товаров, 3 склада, чат, проверка файлов и серверная корзина. Данные — сохранённый снимок из 10 карточек ekt.kz и 3 явно отмеченные учебные позиции.

Статус на 23.09.2026: живые OpenAI и OCR проверены. С локально настроенными ключом и моделью gpt-4.1-mini выполнены реальные вызовы для ответа, разбора запроса и распознавания нового JPEG; повтор OCR использовал кэш. Ключ хранится в локальном .env вне Git. Протокол проверки.

Видео · 73 с, с субтитрами · Русские субтитры · Презентация · Проверки проекта

Подбор электротоваров Проверка спецификации и предложение на одном экране

Проблема и ценность

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

Контур сохраняет основания решения. В поставляемом каталоге у артикула 200300285_ описание указывает 160 А, а свойство — 250 А. Система показывает расхождение и блокирует предложение по спецификации, пока человек не исправит или не исключит проблемную строку. Цена и наличие повторно проверяются при подтверждении.

Результат демонстрации — проверенное предложение на 2 шт за 122 000 ₸. Это стоимость корзины; экономия и сокращение времени закупки на пользователях пока не измерялись.

Что умеет

  • Находить и объяснять: поиск по артикулу/названию, карточка с характеристиками, минимумом заказа, источником и датой снимка; документы показываются при их наличии.
  • Подбирать и уточнять: кандидаты по поддерживаемым требованиям, справочные вопросы о последнем товаре, наличие в Астане, Алматы и Шымкенте, справка по публичным условиям оплаты и доставки ekt.kz с датой и источниками.
  • Проверять основания: конфликтующие поля видны отдельно; неизвестное значение отличается от нуля, общий остаток — от остатка выбранного склада.
  • Разбирать спецификацию: XLSX, DOCX и текстовый PDF локально, новый JPEG через OpenAI в live-режиме, учебный JPEG по записанному результату; исправление количества, единиц и названий, исключение строк, результат проверки рядом с документом.
  • Собирать корзину с подтверждением: добавление, изменение и удаление через конкретное предложение. Серверная корзина сохраняется после перезагрузки; повтор запроса не удваивает операцию.

Архитектура

flowchart LR
    UI[React: запрос или файл] --> API[FastAPI: сессия и валидация]
    API --> RULES[Каталог и правила проверки]
    RULES <--> DB[(SQLite)]
    API --> LLM[app/llm.py: fixtures / OpenAI / fallback]
    RULES --> P[Предложение с ценой и количеством]
    P --> USER[Явное подтверждение человека]
    USER --> CHECK[Повторная проверка сервером]
    CHECK --> DB

Один Python-процесс обслуживает API и готовый web/dist. SQLite хранит каталог, анонимные сессии, документы, предложения и корзины. Модель помогает разбирать информационные запросы и изображения; допустимость покупки, цены и суммы определяют серверные правила. Подтверждается конкретный ID предложения, включая текстовое подтверждение в интерфейсе.

Подробности: архитектура, контракт API, спецификация.

Технологии

Python 3.12, FastAPI, Pydantic, SQLite позволяют запустить всё локально без отдельного сервера БД. OpenAI SDK используется через structured outputs, таймауты, повтор и резервный ответ по правилам.

React, TypeScript, Vite, Tailwind и собственный CSS формируют интерфейс без готовой UI-темы. Lucide, Motion, NumberFlow и шрифты Onest / Unbounded / IBM Plex Mono поставляются локально. CDN в работающем приложении нет. Зависимости закреплены в uv.lock и web/package-lock.json; для запуска готовой сборки Node.js не нужен.

Быстрый старт

С установленными Python 3.12 и uv, из корня клона:

uv run hack serve

Откройте http://127.0.0.1:8000. Команда создаёт отсутствующую data/app.db и обслуживает готовый интерфейс. По умолчанию включён DEMO_MODE=1: .env, личные аккаунты и API-ключи не нужны. Сеть требуется для получения кода и первоначальной установки зависимостей; после установки демонстрация работает автономно.

Установка

Для macOS и Windows 11 с Python 3.12 и uv:

git clone https://github.com/BAITC-Hacks/hack-0a6c3bd5-ai-association.git
cd hack-0a6c3bd5-ai-association
uv sync --frozen
uv run hack serve

Для получения приватного репозитория нужен доступ GitHub; само приложение регистрации не требует. Если порт занят, используйте uv run hack serve --port 8001 и откройте адрес с портом 8001.

Без uv — macOS/Linux:

python3.12 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m app.cli seed
.venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8000

Без uv — Windows 11 PowerShell:

py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m app.cli seed
.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000

seed нужен перед первым прямым запуском uvicorn. При повторном запуске достаточно последней команды; seed не очищает пользовательские корзины.

Docker Compose: docker compose up --build при установленном Docker и запущенном daemon. Команда включает деморежим, сохраняет БД в именованном томе и подключает готовый web/dist из клона только для чтения. Порт 8000 должен быть свободен. На Docker 29.5.2 / Linux python:3.12-slim проверены новая БД и PDF-сценарий desktop/mobile до подтверждённой корзины и перезагрузки. .dockerignore исключает локальные ключи, БД, кэш и окружение из образа. Версии и результаты — FINAL-QA.md.

Переменные окружения

Для демо ничего заполнять не нужно. Для настройки live в новом клоне скопируйте .env.example в .env, задайте свои OPENAI_API_KEY и OPENAI_MODEL и перезапустите сервер. Поля шаблона намеренно оставлены пустыми; при успешной live-проверке ключ и модель были настроены локально. .env исключён из Git.

ПеременнаяПо умолчаниюНазначение
DEMO_MODE1Записанные ответы и локальные правила; 0 включает попытку живого вызова
OPENAI_API_KEYПустоКлюч для live-режима, хранится только локально
OPENAI_MODELПустоЯвно выбранная модель с поддержкой используемых structured outputs; для OCR также нужен ввод изображения
DATABASE_PATHdata/app.db в корне проектаФайл SQLite
ALLOWED_ORIGINShttp://127.0.0.1:5173,http://localhost:5173Разрешённые origin локального Vite; собственный origin сервера также разрешён
EKT_API_USERNAME, EKT_API_PASSWORDПустоТолько для явной команды hack snapshot; обычное демо их не использует

Для явного выбора режима:

uv run hack serve --mode demo
uv run hack serve --mode live

--mode demo принудительно включает автономный режим. --mode live использует ключ и модель из локального .env с приоритетом над унаследованными значениями этих переменных и обращается к https://api.openai.com/v1. Если этих значений в файле нет, можно задать их через окружение; явно пустое значение в .env считается ошибкой. Обычный uv run hack serve сохраняет стандартный выбор по DEMO_MODE; переменные процесса имеют приоритет над .env.

Явный --mode live требует непустые ключ и модель и при их отсутствии завершает запуск с понятной ошибкой. В обычном serve при DEMO_MODE=0 без ключа/модели сохраняется fallback чата на локальные правила. При сетевой ошибке провайдера работающий чат также возвращается к правилам. Новый JPEG без доступного OCR получает понятную ошибку; строки не выдумываются. Поставляемый JPEG использует записанное извлечение даже в live-режиме.

Реальные ответ, разбор запроса и OCR нового JPEG проверены на gpt-4.1-mini; повтор OCR использовал кэш без нового API-вызова. Стандартный live-запуск проверен при устаревших наследованных ключе и модели. Подробности — FINAL-QA.md.

На Windows, если uv не найден в PATH, используйте python -m uv вместо uv. Для отдельного демопоказа при работающем сервере на 8000: python -m uv run hack serve --mode demo --port 8001, адрес http://localhost:8001. Другой порт сам по себе не создаёт отдельную БД; для показа используйте новый профиль браузера с пустой сессией.

Проверка основного сценария

Начните в отдельном профиле браузера с новой сессией и пустой корзиной. Выберите склад «Астана».

  1. Откройте /?view=upload, раскройте «Нет файла? Возьмите учебный образец», скачайте PDF и загрузите его. Появятся две редактируемые строки.
  2. Нажмите «Проверить по каталогу». На том же экране виден конфликт 160 / 250 А у 200300285_: предложения нет, корзина пуста.
  3. Снимите отметку «Включить строку 2» и повторите проверку. Появится предложение 2 шт DEMO-160-AVAILABLE по 61 000 ₸, итог 122 000 ₸. Корзина ещё не изменена.
  4. Нажмите «Проверить и подтвердить», сверьте состав и склад, затем «Подтверждаю добавление». Появится сообщение «Корзина обновлена».
  5. Откройте корзину и перезагрузите страницу: 2 шт и 122 000 ₸ сохраняются.
  6. Установите количество 3 действием строки корзины и подтвердите новое предложение: итог станет 3 шт и 183 000 ₸. Количество в предложении — конечное, а не добавка к имеющемуся.

Без файла начните на / с «Проверь товар 200300285_», затем «Добавь 2 шт DEMO-160-AVAILABLE». Подробный показ — DEMO.md; поиск доступен на /?view=catalog, подтверждённая корзина — на /cart.

Как это масштабируется

Для пилота с партнёром нужны согласованные права на данные, единицы учёта, документы, условия и обновление каталога. app/adapters/ekt.py уже получает отдельные карточки явной командой; полного импорта и обновления по расписанию в демонстрации нет.

Следующий шаг — подключить реальную корзину по предоставленному API, сохранив подтверждение и повторную проверку. Для другого каталога меняются адаптер и предметные правила. Выбор хранилища и масштабирование нагрузки должны опираться на измерения; нагрузочные испытания текущей версии не проводились.

Ограничения и допущения

  • 13 SKU: 10 карточек ekt.kz и 3 синтетические, три склада. Источник и дата сохранены; это снимок, а не полный актуальный каталог. Единица демонстрационного набора задана через demo.unit_override.
  • Неизвестное не равно нулю: null означает отсутствие данных. Локальный и общий остатки различаются. Отсутствующие фото и сертификаты не заменяются вымышленными.
  • Локальная корзина: заказ, оплата и резервирование в ekt.kz не выполняются. Справка по оплате и доставке основана на официальных условиях и FAQ, проверенных 23.09.2026. Способ оплаты, срок и стоимость конкретного заказа подтверждает продавец. Из-за разных порогов бесплатной доставки на сайте прототип не рассчитывает тариф. Неуказанные в предложении позиции сохраняются, итоговое количество 0 означает удаление.
  • Файлы: до 10 MiB, 50 строк; PDF до 10 страниц с текстовым слоем. Старые XLS/DOC и сканированные PDF не поддерживаются. Любая проблемная включённая строка блокирует предложение по всему списку.
  • JPEG: без ключа распознаётся только точный учебный образец. Живой OCR передаёт изображение OpenAI; пользовательские файлы хранятся локально в SQLite своей сессии и не публикуются как статика.
  • Состояние интерфейса: история чата и черновик сохраняются при переходах между экранами, но не после перезагрузки. Подтверждённая корзина восстанавливается через анонимную HttpOnly cookie.

Соответствие критериям задачи

Критерий кейсаРеализованное поведениеГде проверить
Сведения о товаре, характеристики, сертификатыКарточка с исходными полями, источником и документами при наличии/?view=catalog, app/api/catalog.py
Наличие по складуАстана, Алматы, Шымкент; локальный остаток отдельно от общегоВыбор склада, карточка товара
Аналоги и уточняющие вопросыКандидаты по поддерживаемым требованиям, справочный контекст товара, паспорт расхожденийЧат, app/agent/
Оплата, доставка, минимальная партияСправка по публичным условиям с датой и ссылками; минимум из карточки; спорные тарифы не рассчитываются«Какие условия оплаты и доставки?», data/purchase_terms.json
Корзина после подтвержденияКонкретное предложение, явное согласие, повторная проверка, ссылка на корзину/cart, app/commerce.py
Спецификация из файлаИзвлечение, правка/исключение строк, проверка каталога без скрытого добавления/?view=upload, app/documents.py
Запуск без личных доступовДеморежим по умолчанию, готовая сборка и данные в репозиторииБыстрый старт, финальная проверка

Команда

УчастникGitHubВклад
Даниял · Windows 111nkarYBackend, SQLite, агент и правила, документы, API и серверные проверки
Мовсар · macOStranquillwwИнтерфейс, интеграция API, браузерные проверки, документация, демонстрация

Организация работы · Почасовые результаты · Журнал использования Codex

Сторонние компоненты

CREDITS.md раскрывает библиотеки и версии, лицензии, источники каталога, учебные данные и инструменты разработки. Лицензии поставляемых шрифтов и UI-компонентов находятся в web/public/licenses и копируются в web/dist/licenses. Для учебного PDF приложены лицензия DejaVu Sans и сведения о генераторе. Права на исходные материалы ekt.kz не объявляются собственностью команды.

Разработка и проверка

262 backend-теста прошли на macOS и Windows; проверены каталог, сессии, предложения, повторы, четыре формата документов и резервный режим без ключа. На Windows 11 / Python 3.12.3 чистый клон объединённой технической версии 3757794 запущен без .env, ключей и Node: PDF-сценарий на 1440/390 px дал 2 шт / 122 000 ₸ после подтверждения и перезагрузки, без внешних запросов и ошибок JavaScript. Реальные OpenAI/OCR и Docker Compose также проверены. Точные версии, результаты и границы каждого прогона — в FINAL-QA.md.

Backend-тесты из корня: uv run pytest -q. Проверка работающего API: curl http://127.0.0.1:8000/api/health (curl.exe в PowerShell).

Для разработки UI нужны Node.js 22.12+ и npm. Оставьте uv run hack serve на порту 8000; во втором терминале выполните:

cd web
npm ci
npm run dev -- --port 5173 --strictPort

Откройте http://127.0.0.1:5173. Vite проксирует /api на 8000; --strictPort предотвращает переход на другой origin при занятом порте. Команда npm run build в web проверяет TypeScript и создаёт готовый web/dist. Эта папка коммитится; окончательный результат проверяется через FastAPI, чтобы чужому человеку для демонстрации не требовался Node.js. Правила интерфейса — в DESIGN.md.

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

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

tranquillww 16Daniyal Nurlanov 11

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

  • 2026-09-23 17:40H5: явно подтвердить проверку OpenAI и OCR в READMEDaniyal Nurlanov
  • 2026-09-23 17:38H5: результаты Docker, Windows, live и материалы защитыDaniyal Nurlanov
  • 2026-09-23 17:33H5: явный live/demo запуск, чистый Docker и условия ekt.kzDaniyal Nurlanov
  • 2026-09-23 17:22H5: финальный README, чистый комплект и новое видео демонстрацииtranquillww
  • 2026-09-23 17:18H5: очистка старого дизайна и проверка финального интерфейсаtranquillww
  • 2026-09-23 16:55H5: одинаковый SHA-256 лицензии PDF на Windows и macOSDaniyal Nurlanov
  • 2026-09-23 16:55H5: PDF-образец с DejaVu Sans и приложенной лицензиейDaniyal Nurlanov
  • 2026-09-23 16:32H5: видео демо, презентация и подготовка защитыtranquillww
Все коммиты (27)
  • 2026-09-23 16:21H5: проверка редизайна и успешное подтверждение спецификацииtranquillww
  • 2026-09-23 16:16H5: объединение нового интерфейса Claude с актуальным backendtranquillww
  • 2026-09-23 16:14H4: контекст товара и склада для уточнений в диалогеDaniyal Nurlanov
  • 2026-09-23 16:10H5: на телефоне не показываем пустую панель предложенияtranquillww
  • 2026-09-23 16:08H5: понятный путь от запроса или файла до подтверждённой корзиныtranquillww
  • 2026-09-23 15:53H4: автоаналоги и отмена устаревших предложений загрузкиDaniyal Nurlanov
  • 2026-09-23 15:42H4: проверка запуска, документация и передача интерфейса Claudetranquillww
  • 2026-09-23 15:17H3: спецификация из файла, проверка строк и подтверждение комплектаtranquillww
  • 2026-09-23 15:07H4: защита подтверждений после ошибок и проверки интеграцииDaniyal Nurlanov
  • 2026-09-23 14:51H2: чат, проверка подбора и подтверждаемая серверная корзинаtranquillww
  • 2026-09-23 14:46H3: загрузка спецификаций и предложение по проверенным строкамDaniyal Nurlanov
  • 2026-09-23 14:23H2: консультант, проверки каталога и подтверждаемая корзинаDaniyal Nurlanov
  • 2026-09-23 14:22H1: каталог интерфейса подключён к SQLite через APItranquillww
  • 2026-09-23 14:00H1: интерактивный дизайн Контура с проверкой комплектаtranquillww
  • 2026-09-23 13:53H1: SQLite-каталог, API складов и автономный запуск backendDaniyal Nurlanov
  • 2026-09-23 13:32H0: спецификация Контура и контракт API для командыtranquillww
  • 2026-09-23 13:23H0: инструменты Codex и настройка Windowstranquillww
  • 2026-09-23 13:19H0: журнал подготовки совместной работыtranquillww
  • 2026-09-23 13:18H0: организация совместной работы macOS и Windowstranquillww
Структура репозитория (122 файлов)
.dockerignore
.env.example
.gitignore
AGENTS.md
CREDITS.md
Dockerfile
PROGRESS.md
README.md
app/__init__.py
app/adapters/__init__.py
app/adapters/ekt.py
app/agent/__init__.py
app/agent/consultant.py
app/agent/context.py
app/agent/rules.py
app/agent/uploads.py
app/api/__init__.py
app/api/catalog.py
app/api/chat.py
app/api/guards.py
app/api/uploads.py
app/chat_models.py
app/cli.py
app/commerce.py
app/config.py
app/db.py
app/documents.py
app/errors.py
app/llm.py
app/main.py
app/models.py
app/seed.py
app/tests/test_agent.py
app/tests/test_catalog.py
app/tests/test_chat_api.py
app/tests/test_chat_context.py
app/tests/test_commerce.py
app/tests/test_documents.py
app/tests/test_h4_confirmations.py
app/tests/test_ocr.py
app/tests/test_upload_api.py
app/tests/test_upload_matching.py
app/upload_models.py
compose.yaml
data/ekt-snapshot.json
data/products.csv
data/provenance.json
data/purchase_terms.json
data/stock.csv
data/warehouses.csv
docs/API-CONTRACT.md
docs/ARCHITECTURE.md
docs/DEMO.md
docs/DESIGN.md
docs/FINAL-QA.md
docs/PITCH.md
docs/SPEC.md
docs/SUBMISSION.md
docs/TEAM.md
docs/assets/kontur-catalog-desktop.png
docs/assets/kontur-catalog-mobile.png
docs/assets/kontur-chat-desktop.png
docs/assets/kontur-chat-mobile.png
docs/assets/kontur-demo.mp4
docs/assets/kontur-demo.srt
docs/assets/kontur-upload-desktop.png
docs/assets/kontur-upload-mobile.png
docs/codex-log.md
docs/pitch.html
fixtures/.gitignore
fixtures/consultant.json
fixtures/uploads/.gitattributes
fixtures/uploads/jpeg.json
fixtures/uploads/licenses/dejavu-fonts.txt
fixtures/uploads/sample-pdf-provenance.json
fixtures/uploads/sample.docx
fixtures/uploads/sample.jpg
fixtures/uploads/sample.pdf
fixtures/uploads/sample.xlsx
pyproject.toml
requirements.txt
uv.lock
web/index.html
web/package-lock.json
web/package.json
web/public/examples/sample.docx
web/public/examples/sample.jpg
web/public/examples/sample.pdf
web/public/examples/sample.xlsx
web/public/favicon.svg
web/public/licenses/clsx.txt
web/public/licenses/ibm-plex-mono.txt
web/public/licenses/lucide.txt
web/public/licenses/motion.txt
web/public/licenses/number-flow.txt
web/public/licenses/onest.txt
web/public/licenses/react-dom.txt
web/public/licenses/react.txt
web/public/licenses/unbounded.txt
web/src/App.tsx
web/src/CartPanel.tsx
web/src/CatalogPanel.tsx
web/src/ChatPanel.tsx
web/src/UploadPanel.tsx
web/src/UploadResult.tsx
web/src/api.ts
web/src/catalog.css
web/src/checkout.css
web/src/commerce.css
web/src/format.ts
web/src/kontur.css
web/src/main.tsx
web/src/path.tsx
web/src/proposal.tsx
web/src/styles.css
web/src/upload.css
web/src/useCommerce.ts
web/src/vite-env.d.ts
web/tsconfig.app.json
web/tsconfig.json
web/tsconfig.node.json
web/vite.config.ts

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

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

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