О проекте
Команда: < blank >
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: Автоматический расчёт заказов поставщикам для пополнения склада, с утверждением менеджером
Суть
Локальное Streamlit-приложение для закупщика: импорт XLSX Systeme Electric и IEK, прогноз спроса, расчёт пополнения и проекты заказов поставщикам с корректировкой и утверждением менеджером.
Как устроено
XLSX-книги поставщиков импортируются с прослеживаемостью до ячейки и версионированием в SQLite; спрос очищается от возвратов и разовых сделок, оценивается упущенный спрос при отсутствии товара. Прогноз выбирается из трёх моделей (seasonal_analog, damped_level_trend, Croston SBA) по бэктесту, затем потребность = прогноз за (L+R) + страховой запас − остаток − поступления с учётом MOQ и кратности. Менеджер корректирует, утверждает версию заказа и выгружает CSV/XLSX.
Ключевые решения
- Croston SBA
- damped level trend
- сезонный аналог
- rolling-origin бэктест (WAPE, MAE)
- страховой запас
- MOQ и кратность
- оценка упущенного спроса
Особенности
Без LLM, но с продуманной методологией: отдельная обработка возвратов, разовых сделок и упущенного спроса, выбор модели по временной валидации, версионирование утверждённых заказов и аудит правок с автором и причиной.
Стек
Python · Streamlit · SQLite · openpyxl · uv · pytest
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-3b47610b-blank.
README
README.mdПомощник закупщика — StockForge
Локальное приложение для расчёта пополнения склада и подготовки объяснимых заказов поставщикам. Разработано для кейса ТОО «Электрокомплект» на хакатоне HackAlem.
Для кого: менеджер отдела закупок, который объединяет отчёты и рассчитывает потребность вручную в Excel. Приложение связывает продажи, остатки, ожидаемые поступления и закупочные условия, показывает рекомендуемое количество и основания для него. Менеджер проверяет результат, корректирует и утверждает версию заказа.
Текущая версия: локальный MVP с русскоязычным интерфейсом и воспроизводимой синтетической демонстрацией. Реальные файлы импортируются и проверяются; подтверждённые реальные заказы на имеющемся наборе заблокированы до согласования недостающих данных и условий.
Репозиторий · Демонстрация на 6 минут · Отчёт приёмки · Статус реализации
Что реализовано
| Возможность | Что получает пользователь |
|---|---|
| Импорт Systeme Electric и IEK | Загрузка шести XLSX-книг каждого поставщика, включая скрытые листы и встроенный архивный прайс IEK. Значения прослеживаются до файла, листа и ячейки. |
| Версии и проверки данных | Повторный импорт неизменённых файлов не дублирует данные; изменённый файл создаёт новую версию. Пустоты, нули, ошибки и расхождения источников показываются отдельно. |
| Подготовка регулярного спроса | Возвраты учитываются отдельно; разовые крупные сделки выделяются для проверки или исключения по заданному правилу. Повторные крупные покупки и устойчивый рост сохраняются. |
| Прогноз спроса | Месячный прогноз с сезонностью, трендом, обработкой прерывистого спроса и явными настройками бизнес-прироста. Модели сравниваются на прошлых временных периодах. |
| Упущенный спрос | Оценка потерь при подтверждённом полнодневном отсутствии товара. Коррекция входит в историю для прогноза и не превращается в текущую задолженность. |
| Пополнение и сценарии | Учёт доступного остатка, поступлений, сроков, политики категории, страхового запаса, единиц, MOQ и кратности. Проверка задержки поставки и изменения спроса. |
| Объяснения | Карточка товара с компонентами формулы, источниками, допущениями, прогнозом остатка и риском дефицита. |
| Работа с заказами | Проекты по поставщикам, корректировки с автором и причиной, проверка и утверждение. Утверждённая версия сохраняется; последующая правка создаёт новую. |
| Экспорт и воспроизводимость | Проверяемые CSV/XLSX, чтение расчётов по run_id, CLI, синтетическое демо и резервные копии SQLite. |
Как работает решение
- Загрузить данные. Импортировать отчёты поставщика либо открыть готовый синтетический набор.
- Проверить входы. Изучить расхождения, выбрать источник продаж и задать закупочные параметры с автором, основанием и статусом подтверждения.
- Подготовить спрос. Отделить регулярные продажи от возвратов и разовых сделок; при наличии доказательств учесть периоды отсутствия товара.
- Получить рекомендации. Выбрать совместимые версии данных, подготовки и прогноза. Сохранить расчёт и проверить строки в карточках товаров.
- Проверить риск. Посмотреть календарь остатка и при необходимости создать отдельный сценарий задержки или изменения спроса.
- Сформировать заказ. Скорректировать количества, передать проект на проверку, утвердить и выгрузить CSV/XLSX.
В интерфейсе доступны пять разделов: «Данные и проверки», «Рекомендации», «Карточка товара», «Сценарии», «Заказы».
Расчёт и объяснение количества
Базовая потребность в единицах учёта:
max(0, прогноз спроса за (L + R) + страховой запас
− доступный остаток − своевременные ожидаемые поступления)
L — срок нового заказа, R — период пересмотра. Резерв уменьшает доступный остаток один раз; проектные обязательства учитываются отдельно от регулярного спроса. Потребность сначала переводится в единицу закупки, затем применяются MOQ (минимальная партия) и кратность. При нулевой потребности MOQ не создаёт заказ.
Например: 300 + 60 − 90 − 100 = 170; кратность 12 даёт заказ 180. Поздний приход не считается прибывшим. Если дефицит возникает раньше обычного нового заказа, приложение выделяет срочную проблему.
Текст обоснования создаётся из сохранённых компонентов расчёта. Полные правила: пополнение, прогноз, упущенный спрос.
Технологии и модели
| Компонент | Реализация |
|---|---|
| Язык | Python; в pyproject.toml указан диапазон >=3.11,<3.15. Проверенное окружение — Python 3.14.7. |
| Интерфейс | Streamlit: таблицы, формы, графики st.line_chart, скачивание файлов. |
| Excel | openpyxl; стандартные средства Python для чтения XML и встроенного кэша XLSX. |
| Хранилище | SQLite через стандартный модуль sqlite3: источники, параметры, расчёты, проекты заказов и журнал изменений. |
| Расчётное ядро | Собственный Python-код, не зависящий от Streamlit. |
| Проверки | pytest, Streamlit AppTest, синтетический эталон и проверки реальных книг при их наличии. |
| Окружение | uv, pyproject.toml и закреплённые зависимости в uv.lock. |
В зависимостях также объявлены pandas, NumPy и Plotly. Текущее расчётное ядро реализовано собственным кодом Python, а графики интерфейса строятся средствами Streamlit.
Прогноз выбирается из трёх статистических моделей:
seasonal_analog— тот же календарный месяц прошлого года;damped_level_trend— сглаженный уровень и затухающий тренд;intermittent_sba— метод Croston с поправкой SBA для прерывистого спроса.
Проверка идёт последовательно по времени: модель учится на прошлом и прогнозирует следующий период. Отчёт содержит WAPE (относительную взвешенную ошибку), MAE (среднюю абсолютную ошибку), смещение и сравнение с простыми базовыми прогнозами. Неполный текущий месяц исключается из обучения.
Внешние LLM, генеративные AI-модели и API-сервисы в приложении не используются. API-ключи для запуска не нужны; после установки зависимостей расчёты выполняются локально.
Архитектура проекта
flowchart LR
A["XLSX / синтетические наблюдения"] --> B["Импорт и проверка качества"]
B --> C[("SQLite: источники и версии")]
C --> D["Подготовка спроса → прогноз → пополнение"]
D --> C
D --> E["Рекомендации в Streamlit / CLI"]
E --> F["Корректировка и утверждение"]
F --> C
F --> G["CSV / XLSX"]
Интерфейс и CLI обращаются к общему слою сервисов. Сервисы проверяют совместимость входных версий, вызывают расчётное ядро и сохраняют результат. Прогноз и пополнение не требуют запуска браузера.
| Путь | Назначение |
|---|---|
app.py, hackalem/ui/ | Точка входа и рабочее место закупщика. |
hackalem/__main__.py | CLI для импорта, расчётов, отчётов, заказов, демо и резервных копий. |
hackalem/importers/ | Адаптеры форматов Systeme Electric и IEK. |
hackalem/services/ | Связь импорта, проверок, подготовки спроса, прогнозов, пополнения и заказов. |
hackalem/domain/ | Правила очистки, оценки потерь, прогнозирования и расчёта количества. |
hackalem/storage.py, hackalem/*_schema.py | Создание и миграции SQLite, схемы данных. |
hackalem/config.py | Пути источников и локального хранилища. |
hackalem/synthetic/ | Генератор наблюдений и спецификация проверочного набора. |
tests/, scripts/ | Тесты и воспроизводимые замеры реального/синтетического набора. |
docs/, DEMO.md | Контракты данных, методология, результаты приёмки и сценарий защиты. |
Установка и запуск
Команды ниже предназначены для Windows PowerShell. Нужны Git, Python 3.11–3.14 и uv. Git и uv должны быть доступны в терминале. Если uv ещё не установлен:
py -m pip install --user uv
Откройте новый терминал после установки. На машине разработки проверены Python 3.14.7 и uv 0.12.13. При первой установке пакетов нужен интернет; Docker и отдельный сервер БД не требуются.
1. Получить проект и установить зависимости
git clone https://github.com/BAITC-Hacks/hack-3b47610b-blank.git
Set-Location .\hack-3b47610b-blank
uv sync --locked
Если репозиторий уже открыт локально, перейдите в его корень и выполните только uv sync --locked. Все дальнейшие команды выполняются из корня проекта. Активировать виртуальное окружение и менять ExecutionPolicy не требуется.
2. Подготовить демонстрацию
Конфиденциальные файлы поставщиков для этого пути не нужны:
uv run --locked python -m hackalem demo --output-root .local/demo
$demo = Get-Content -Raw -Encoding UTF8 '.local/demo/demo-v1-20260923/demo-manifest.json' | ConvertFrom-Json
$env:HACKALEM_DATA_DIR = Split-Path -Parent $demo.database_path
Команда создаёт отдельный набор из 17 вымышленных товаров двух поставщиков. Для выбранных примеров подготовлены 11 прогнозов, 3 расчёта пополнения, проекты заказов и 8 проверенных выгрузок. Срез демо фиксирован: 01.01.2026, seed — 20260923.
Манифест содержит пути, номера снимков, run_id и версии заказов. В папке .local/demo/demo-v1-20260923/ находятся reports/ с объяснениями и exports/ с CSV/XLSX. Все демо-заказы имеют маркировку SYNTHETIC_SCENARIO.
Повторный вызов проверяет и использует готовый набор. Для новой демонстрации выберите другой --output-root и прочитайте манифест из него. Существующая незавершённая или повреждённая папка автоматически не перезаписывается.
3. Открыть приложение
uv run --locked python -m streamlit run app.py
Откройте http://127.0.0.1:8501. Сервер слушает локальный адрес, сбор статистики Streamlit отключён. Для остановки нажмите Ctrl+C. Если порт занят:
uv run --locked python -m streamlit run app.py --server.port 8502
В этом случае откройте http://127.0.0.1:8502.
Запуск с реальными файлами
Поместите выданные организаторами книги в папки IEK и Systeme electric внутри отдельного каталога источников. Форматы ожидаемых шести книг каждого поставщика описаны в контракте Systeme и контракте IEK; произвольный Excel не является поддержанным форматом импорта.
После остановки демо задайте пути, заменив путь источников своим:
$env:HACKALEM_SOURCE_DIR = 'C:\HackAlemData'
$env:HACKALEM_DATA_DIR = '.local/real'
uv run --locked python -m hackalem import-systeme
uv run --locked python -m hackalem import-iek
uv run --locked python -m hackalem list-snapshots
uv run --locked python -m streamlit run app.py
В интерфейсе импорт также доступен в разделе «Данные и проверки». Исходный сценарий реальных данных привязан к 22.09.2026; дата компьютера его не заменяет. Без согласованных параметров приложение показывает причины недоступности расчёта. Параметры и выбор источников задаются через JSON по контракту данных.
| Настройка | Значение по умолчанию |
|---|---|
HACKALEM_SOURCE_DIR | Корень проекта с папками поставщиков. |
HACKALEM_DATA_DIR | .local; БД — hackalem.sqlite3 внутри выбранной папки. |
HACKALEM_REAL_SOURCE_DIR | Путь к исходникам для тестов реальных книг; по умолчанию корень проекта. |
Относительные пути HACKALEM_SOURCE_DIR и HACKALEM_DATA_DIR разрешаются от корня проекта. Переменные действуют в текущем терминале; .env автоматически не читается. Хранилище нельзя размещать внутри папок поставщиков. Реальная и демонстрационная базы должны оставаться раздельными.
Резервная копия и восстановление
db-backup копирует выбранную через HACKALEM_DATA_DIR базу с помощью SQLite Online Backup API, включая закоммиченные данные WAL. Команда не заменяет существующий файл:
$backupPath = '.local/backups/hackalem-' + (Get-Date -Format 'yyyyMMdd-HHmmss') + '.sqlite3'
uv run --locked python -m hackalem db-backup --output $backupPath
Для восстановления остановите сервер, сохраните прежний путь базы и выберите новую пустую папку:
$env:HACKALEM_DATA_DIR = '.local/restored'
uv run --locked python -m hackalem db-restore --input $backupPath
uv run --locked python -m hackalem list-snapshots
uv run --locked python -m streamlit run app.py
Если целевой файл уже существует, выберите другое имя папки. Храните резервную копию, исходники и версию кода с uv.lock на защищённом носителе. Для повторной проверки синтетического эталона нужна вся папка набора: manifest.json, model/ и validation/, а не только БД.
Как проверить решение жюри
После запуска демо выберите синтетический Dataset и дату 01.01.2026. Номера версий берите из манифеста:
$demo.snapshots | Format-Table
$demo.replenishment_run_ids
$demo.orders
Эти команды можно выполнить перед запуском сервера в том же терминале. Затем повторите сценарий в браузере:
| Шаг | Действие | Ожидаемый результат |
|---|---|---|
| 1. Обычный заказ | Выберите снимок Systeme Electric. В «Рекомендациях» и «Карточке товара» выберите сохранённый расчёт Systeme; откройте SYN-A-001. | Количество, единицы, компоненты формулы, источники и будущий остаток доступны для проверки. |
| 2. Сезонность и рост | В карточке выберите SYN-A-002, затем SYN-A-003. | Прогноз отражает сезонную форму и растущий спрос. |
| 3. Разовая сделка | Откройте SYN-A-006, график фактического/очищенного спроса и блок аномалий. | Разовая сделка 500 выделена из регулярной части. |
| 4. Отсутствие товара | Откройте SYN-A-009, блок наличия и упущенного спроса. Сравните reports/stockout-raw-forecast.json и reports/forecast-SYN-A-009.json. | В исторической проверке прогноз августа меняется с 119 до 217 при известном синтетическом спросе 217. |
| 5. Задержка | Переключитесь на снимок IEK, выберите SYN-B-003; сравните сохранённые расчёты IEK и delay из манифеста. | Задержка поступления на 14 дней вызывает срочный риск до прихода обычного нового заказа. |
| 6. Утверждение | В «Заказах» выберите подготовленный черновик. Укажите автора/причину передачи на проверку, затем ответственного/основание утверждения и подтвердите локальный характер записи имени. | Версия проходит draft → review → approved; предыдущий утверждённый снимок сохраняется. |
| 7. Экспорт | Отметьте «Выгрузить с этой маркировкой» и скачайте CSV или Excel. | Файл содержит поставщика, товары, количества, единицы и объяснения; маркировка — SYNTHETIC_SCENARIO. |
Для нового расчёта в «Рекомендациях» выберите совместимые качество, подготовку спроса и прогнозы товаров, затем нажмите «Рассчитать рекомендации». Смена даты или входной версии сбрасывает активный выбор старого результата; сохранённые расчёты остаются доступны для явного выбора.
Подробный сценарий защиты и команды проверки без UI — в DEMO.md. Например, после остановки сервера в том же терминале:
uv run --locked python -m hackalem replenishment-report --run $demo.replenishment_run_ids.'Systeme Electric' --sku SYN-A-001
uv run --locked python -m hackalem order-report --version $demo.orders.IEK.approved_version_id
Автоматические проверки
uv run --locked python -m pytest -q
В приёмке от 23.09.2026 зафиксированы 156 прошедших тестов, включая реальные книги обоих поставщиков. Без конфиденциальных исходников соответствующие тесты пропускаются. Проверяются импорт и версии, расчёты, пограничные случаи, сохранение утверждённых заказов, экспорт, восстановление БД и пользовательский сценарий через AppTest.
Для воспроизводимой проверки синтетической истории и замера времени:
uv run --locked python -m scripts.benchmark_demo --output-dir .local/demo-validation
Выходная папка должна быть новой. В ней сохраняются acceptance-history.json, benchmark.json и профили. Скрытый истинный спрос читает только проверяющая процедура после работы модели. Тесты на синтетических данных не доказывают точность прогноза или экономию в реальном бизнесе.
Данные и интеграции
Реальные источники: локальные XLSX-выгрузки Systeme Electric и IEK — история продаж, месячные показатели, остатки, поступления, категории и условия заказа. Для IEK читается встроенный архивный прайс; внешние связи Excel не обновляются. В зафиксированной приёмке обработаны 12 книг и 248 915 транзакционных строк. Структура и ограничения источников описаны в документах импорта.
Демонстрационные данные: воспроизводимые наблюдения за 2024–2025 годы для 17 вымышленных товаров. Набор включает стабильный, сезонный, растущий и прерывистый спрос, разовые сделки, возвраты, отсутствие товара, задержки и ограничения закупки.
Интеграции: файловый импорт XLSX и экспорт CSV/XLSX. Прямое подключение к 1С, ERP, API поставщиков и внешним AI-сервисам не реализовано. Совместимость выгрузки с конкретной конфигурацией 1С требует согласованного шаблона и пробного импорта.
Исходные PDF/XLSX не изменяются. Конфиденциальные книги, локальная БД, секреты и создаваемые выгрузки исключены из Git. Реальные данные во внешние сервисы приложение не отправляет; идентификаторы клиентов для анализа должны быть обезличены.
Ограничения текущей версии
- Не хватает подтверждённых реальных входов. Среди них актуальный остаток IEK, дневное наличие товара, обезличенные клиенты, сроки поставки/пересмотра, политика категории, единицы и коэффициенты, действующие MOQ/кратности и полные даты поступлений. Архивные условия не считаются автоматически действующими.
- Складской охват ограничен исходным отчётом. Достоверное раздельное прогнозирование по складам не реализовано. Бизнес-параметры пока вводятся через JSON.
- Есть явные допущения. Страховой запас задаётся в днях; статистическая калибровка уровня обслуживания не заявлена. Месячный прогноз распределяется равномерно по дням, поэтому дата риска приблизительна. Если истории меньше 12 завершённых месяцев, нужен явно заданный прогноз по категории; без него прогноз не строится.
- Выбросы и stockout требуют доказательств. Без клиента/контекста крупная сделка остаётся кандидатом. Месячный остаток не определяет дни отсутствия; ручные интервалы дают только сценарную оценку.
- Утверждение локальное. Имя ответственного — запись в журнале, а не аутентификация или электронная подпись. Отправки заказов поставщикам нет.
- Нет готовой промышленной интеграции. Шаблон 1С и её импорт не прошли приёмку; облачное развёртывание не подготовлено. Экономия и точность на реальном спросе не доказаны.
Развёрнутая версия
Публичный адрес работающего приложения в текущем репозитории не указан. Предусмотрен локальный запуск по инструкции выше. Адрес http://127.0.0.1:8501 доступен на компьютере, где запущен Streamlit, и не является публичной демо-ссылкой.
Дополнительная документация
| Документ | Содержание |
|---|---|
| DEMO.md | Защита на 5–7 минут, ожидаемые примеры и проверка через CLI. |
| SPEC.md, STATUS.md | Требования кейса и фактическое состояние реализации. |
| ACCEPTANCE.md | Пять обязательных требований, результаты тестов, историческая проверка и замеры. |
| DATA_CONTRACT.md | Источники продаж, бизнес-параметры и правила готовности данных. |
| SYNTHETIC_DATA.md | Генератор, скрытый эталон и заранее заданные критерии. |
| FORECASTING.md, LOST_DEMAND.md | Методология прогноза и оценки упущенного спроса. |
| REPLENISHMENT.md, ORDERS.md | Формула, воспроизводимость, корректировки, утверждение и экспорт. |
Авторы коммитов
История коммитов
- 2026-09-23 17:47Update README.mdboztayevs
- 2026-09-23 17:45docs: rewrite README for hackathon jurySanzhar
- 2026-09-23 17:38feat: complete MVP acceptance and reproducible demoSanzhar
- 2026-09-23 17:22feat: connect demand planning to reviewed supplier ordersSanzhar
- 2026-09-23 16:30feat: add versioned seasonal demand forecastingRakhat
- 2026-09-23 16:30docs: document forecast workflow and validationRakhat
- 2026-09-23 16:04feat: prepare regular demand with reviewable returns and one-offsSanzhar
- 2026-09-23 16:03feat: add versioned data quality and synthetic validationSanzhar
Все коммиты (9)
- 2026-09-23 15:03feat: implement HackAlem foundation and supplier imports (stages 1-3)Sanzhar
Структура репозитория (96 файлов)
.gitignore .python-version .streamlit/config.toml AGENTS.md DEMO.md README.md app.py docs/ACCEPTANCE.md docs/DATA_CONTRACT.md docs/FORECASTING.md docs/IMPORT_IEK.md docs/IMPORT_SYSTEME.md docs/LOST_DEMAND.md docs/ORDERS.md docs/REPLENISHMENT.md docs/SPEC.md docs/STATUS.md docs/SYNTHETIC_DATA.md hackalem/__init__.py hackalem/__main__.py hackalem/cleaning_schema.py hackalem/config.py hackalem/domain/__init__.py hackalem/domain/cleaning.py hackalem/domain/forecasting.py hackalem/domain/lost_demand.py hackalem/domain/quality_config.py hackalem/domain/replenishment.py hackalem/forecast_schema.py hackalem/import_schema.py hackalem/importers/__init__.py hackalem/importers/iek.py hackalem/importers/iek_cache.py hackalem/importers/systeme.py hackalem/lost_demand_schema.py hackalem/orders_schema.py hackalem/quality_schema.py hackalem/replenishment_schema.py hackalem/services/__init__.py hackalem/services/backup.py hackalem/services/bootstrap.py hackalem/services/cleaning.py hackalem/services/datasets.py hackalem/services/demo.py hackalem/services/forecasting.py hackalem/services/imports.py hackalem/services/lost_demand.py hackalem/services/orders.py hackalem/services/quality.py hackalem/services/reconciliation.py hackalem/services/replenishment.py hackalem/services/synthetic.py hackalem/services/systeme.py hackalem/services/units.py hackalem/storage.py hackalem/synthetic/__init__.py hackalem/synthetic/generator.py hackalem/synthetic/validation_spec.json hackalem/ui/__init__.py hackalem/ui/cleaning_panel.py hackalem/ui/forecast_panel.py hackalem/ui/home.py hackalem/ui/lost_demand_panel.py hackalem/ui/procurement_panel.py hackalem/ui/quality_panel.py pyproject.toml scripts/benchmark_demo.py scripts/benchmark_real.py tests/test_app.py tests/test_backup.py tests/test_bootstrap.py tests/test_case_acceptance.py tests/test_cleaning.py tests/test_cleaning_app.py tests/test_demo.py tests/test_forecasting.py tests/test_iek_parser.py tests/test_iek_real.py tests/test_import_versions.py tests/test_lost_demand.py tests/test_lost_demand_app.py tests/test_orders.py tests/test_procurement_app.py tests/test_quality.py tests/test_quality_app.py tests/test_quality_cli.py tests/test_reconciliation.py tests/test_replenishment.py tests/test_synthetic.py tests/test_synthetic_app.py tests/test_synthetic_cli.py tests/test_synthetic_reference.py tests/test_systeme_parser.py tests/test_systeme_real.py tests/test_units_and_migration.py uv.lock
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.