О проекте
Команда: SKMA - MedMind
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: Автоматический расчёт заказов поставщикам для пополнения склада, с утверждением менеджером
Суть
Сервис для закупщиков Электрокомплекта: собирает отчёты поставщиков IEK и Systeme Electric и рассчитывает, что и сколько заказать. Менеджер проверяет, правит и утверждает позиции, результат выгружается в файл. Есть ИИ-ассистент.
Как устроено
ETL-модули (etl/iek.py, etl/systeme.py) загружают Excel-отчёты в БД, демо-данные подгружаются из jsonl.gz. Движок (engine/core, timeseries, explain) учитывает продажи, сезонность, остатки, резервы, товары в пути, сроки поставки, минимальную партию и кратность и объясняет каждую рекомендацию. Расчёт запускается командой hackalem calc. Фронтенд показывает дашборд, заказы, товары и историю продаж. ИИ-ассистент с инструментами (assistant/tools.py) строит графики и предлагает утвердить заказ прямо в чате.
Ключевые решения
- сезонность
- страховой запас/срок поставки
- MOQ/кратность
- ETL Excel
- tool-calling ассистент
Особенности
ИИ-ассистент с инструментами строит графики и показывает компонент утверждения заказа (OrderApproval) прямо в диалоге. Всё запускается одной командой docker compose с автоматической загрузкой демо-данных.
Стек
Python · uv · React (TSX) · Docker Compose · nginx
Модели
OpenAI API
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-8cf29c0a-skma---medmind.
README
README.mdЭКТ Автозаказ
Что это за проект и какие задачи он решает
ЭКТ Автозаказ — помощник для менеджеров по закупкам ТОО «Электрокомплект». Он подсказывает, какие товары пора заказать у поставщиков и в каком количестве, чтобы снижать риск нехватки товара и не накапливать лишние запасы на складе.
При работе с большими таблицами сложно сопоставить продажи, остатки и ожидаемые поставки. Проект помогает:
- Сократить ручные расчёты: собирает данные из отчётов поставщиков IEK и Systeme Electric и готовит рекомендации по закупке.
- Вовремя пополнить склад: учитывает продажи, сезонность, остатки, резервы, товары в пути и сроки поставки.
- Избежать лишних закупок: учитывает уже доступный и заказанный товар, минимальную партию и кратность заказа.
- Понять рекомендацию: показывает причины расчёта и срочность закупки, позволяет проверить и изменить количество.
- Подготовить заказ: менеджер проверяет позиции, утверждает их и выгружает результат в файл.
Окончательное решение остаётся за менеджером: утверждение в системе не отправляет заказ поставщику автоматически.
Запуск через Docker
Подготовка
Понадобится установленный и запущенный Docker Desktop в режиме Linux containers или Docker Engine с Compose v2. Отдельно устанавливать Python, Node.js и базу данных не нужно.
Скачайте проект и откройте терминал в его корневой папке — там, где находится файл compose.yaml. Все команды ниже выполняются из этой папки и подходят для PowerShell, Bash и терминала macOS.
Проверьте, что Docker доступен:
docker --version
docker compose version
Если команда docker не найдена, убедитесь, что Docker установлен, и заново откройте терминал после установки.
Первый запуск
Запустите приложение одной командой:
docker compose up --build -d
При первом запуске нужен интернет: Docker скачает зависимости и соберёт приложение. Дождитесь завершения команды — первая подготовка может занять несколько минут.
Откройте приложение в браузере: http://localhost:8080.
В пустую базу автоматически загрузятся тестовые данные, поэтому для знакомства с проектом свои Excel-файлы не нужны. При повторном запуске существующие данные сохраняются.
Расчёт рекомендаций
Тестовые данные содержат готовые заказы, но не прогнозы. Чтобы получить новый расчёт и подробные обоснования, выполните:
docker compose exec backend hackalem calc
После завершения обновите страницу и выберите новый расчёт в шапке приложения.
Остановка и повторный запуск
Остановить приложение:
docker compose down
Данные сохранятся в Docker-томе. Для повторного запуска:
docker compose up -d
После обновления кода пересоберите приложение:
docker compose up --build -d
Если приложение не открывается
Убедитесь, что Docker запущен, затем проверьте состояние контейнеров и сообщения об ошибках:
docker compose ps
docker compose logs -f
Выйти из просмотра сообщений можно сочетанием Ctrl+C — приложение продолжит работать.
Дополнительные настройки
Для обычного запуска файл .env не нужен. Чтобы изменить порт или включить ИИ-ассистента, скопируйте .env.example в .env в корне проекта, рядом с compose.yaml. Если .env уже есть, отредактируйте его:
APP_PORT=8081— открыть приложение по адресу http://localhost:8081, если порт 8080 занят.OPENAI_API_KEY=ваш_ключ— включить ИИ-ассистента. Без ключа остальные функции доступны.
После изменения настроек выполните docker compose up -d.
Авторы коммитов
История коммитов
- 2026-09-23 17:54Последние правкиs-webs
- 2026-09-23 17:49Обновил READMEs-webs
- 2026-09-23 17:42Реализовал ИИ ассистентаs-webs
- 2026-09-23 16:34Сделал историю продажnas-kz
- 2026-09-23 16:27Рализован frontend часть управления товарамиmaxatjd-ux
- 2026-09-23 15:30Начал работу над бэкэндомs-webs
- 2026-09-23 15:16сделал экран заказов с тестовыми даннымиnas-kz
- 2026-09-23 15:02Сделал экран дашборда с тестовыми даннымиmaxatjd-ux
Все коммиты (11)
- 2026-09-23 14:44Добавил правило и дизайн систему, разработал базовый app shells-webs
- 2026-09-23 13:58Добавил тз по фронтуs-webs
- 2026-09-23 13:48Добавил architecture.mds-webs
Структура репозитория (168 файлов)
.env.example .gitignore AGENTS.md ARCHITECTURE.md DESIGN.md FRONTEND_TZ.md README.md backend/.dockerignore backend/.env.example backend/.gitignore backend/.python-version backend/Dockerfile backend/INPUT_DATA.md backend/README.md backend/docker-entrypoint.py backend/pyproject.toml backend/scripts/export_seed.py backend/src/app/__init__.py backend/src/app/api/__init__.py backend/src/app/api/analytics.py backend/src/app/api/assistant.py backend/src/app/api/calc_runs.py backend/src/app/api/catalog.py backend/src/app/api/imports.py backend/src/app/api/input_data.py backend/src/app/api/recommendations.py backend/src/app/api/settings.py backend/src/app/api/workspace.py backend/src/app/assistant/__init__.py backend/src/app/assistant/agent.py backend/src/app/assistant/charts.py backend/src/app/assistant/schemas.py backend/src/app/assistant/tools.py backend/src/app/cli.py backend/src/app/config.py backend/src/app/db.py backend/src/app/engine/__init__.py backend/src/app/engine/core.py backend/src/app/engine/explain.py backend/src/app/engine/timeseries.py backend/src/app/etl/__init__.py backend/src/app/etl/common.py backend/src/app/etl/iek.py backend/src/app/etl/loader.py backend/src/app/etl/systeme.py backend/src/app/input_schemas.py backend/src/app/main.py backend/src/app/models.py backend/src/app/schemas.py backend/src/app/seed_data/assistant_conversations.jsonl.gz backend/src/app/seed_data/assistant_files.jsonl.gz backend/src/app/seed_data/assistant_messages.jsonl.gz backend/src/app/seed_data/audit_log.jsonl.gz backend/src/app/seed_data/calc_params.jsonl.gz backend/src/app/seed_data/calc_runs.jsonl.gz backend/src/app/seed_data/categories.jsonl.gz backend/src/app/seed_data/goods_in_transit.jsonl.gz backend/src/app/seed_data/import_identities.jsonl.gz backend/src/app/seed_data/manifest.json backend/src/app/seed_data/order_recommendations.jsonl.gz backend/src/app/seed_data/reference_metrics.jsonl.gz backend/src/app/seed_data/sales_lines.jsonl.gz backend/src/app/seed_data/skus.jsonl.gz backend/src/app/seed_data/stock_current.jsonl.gz backend/src/app/seed_data/stock_monthly.jsonl.gz backend/src/app/seed_data/supplier_rules.jsonl.gz backend/src/app/seed_data/supplier_seasonality.jsonl.gz backend/src/app/seed_data/suppliers.jsonl.gz backend/src/app/services/__init__.py backend/src/app/services/analytics.py backend/src/app/services/assistant_files.py backend/src/app/services/assistant_settings.py backend/src/app/services/bundle_import.py backend/src/app/services/calc_runs.py backend/src/app/services/exporter.py backend/src/app/services/input_data.py backend/src/app/services/seed.py backend/src/app/services/tabular_import.py backend/tests/conftest.py backend/tests/test_api.py backend/tests/test_assistant.py backend/tests/test_assistant_settings.py backend/tests/test_engine.py backend/tests/test_inputs.py backend/tests/test_orders_crud.py backend/tests/test_seed.py backend/tests/test_workspace.py backend/uv.lock compose.yaml frontend/.dockerignore frontend/.env.example frontend/.gitignore frontend/.oxlintrc.json frontend/Dockerfile frontend/README.md frontend/index.html frontend/nginx.conf frontend/package-lock.json frontend/package.json frontend/postcss.config.js frontend/public/favicon.svg frontend/public/icons.svg frontend/src/app/App.tsx frontend/src/app/Layout.tsx frontend/src/app/router.tsx frontend/src/features/assistant/AssistantChart.tsx frontend/src/features/assistant/Composer.tsx frontend/src/features/assistant/Markdown.tsx frontend/src/features/assistant/MessageItem.tsx frontend/src/features/assistant/OrderApproval.tsx frontend/src/features/assistant/mock.ts frontend/src/features/assistant/model.ts frontend/src/features/assistant/types.ts frontend/src/features/orders/MultiSelect.tsx frontend/src/features/orders/OrderBadge.tsx frontend/src/features/orders/OrderEditor.tsx frontend/src/features/orders/OrdersTable.tsx frontend/src/features/orders/mock.ts frontend/src/features/orders/model.ts frontend/src/features/sales/SalesTrend.tsx frontend/src/features/sales/model.ts frontend/src/index.css frontend/src/main.tsx frontend/src/pages/AssistantPage/index.tsx frontend/src/pages/DashboardPage/index.tsx frontend/src/pages/DashboardPage/mockData.ts frontend/src/pages/OrderDetailDrawer/index.tsx frontend/src/pages/OrdersPage/index.tsx frontend/src/pages/ProductsPage/ProductEditor.tsx frontend/src/pages/ProductsPage/SupplierImport.tsx frontend/src/pages/ProductsPage/index.tsx frontend/src/pages/ProductsPage/model.ts frontend/src/pages/SalesHistoryPage/index.tsx frontend/src/pages/SettingsPage/AssistantSettings.tsx frontend/src/pages/SettingsPage/index.tsx frontend/src/pages/SettingsPage/model.ts frontend/src/shared/api/assistant.ts frontend/src/shared/api/client.ts frontend/src/shared/api/fixtures/calc-runs.json frontend/src/shared/api/fixtures/orders.json frontend/src/shared/api/orders.ts frontend/src/shared/api/settings.ts frontend/src/shared/api/types.ts frontend/src/shared/calc-run/CalcRunContext.tsx frontend/src/shared/calc-run/useCalcRun.ts frontend/src/shared/theme/ThemeContext.tsx frontend/src/shared/ui/Button.tsx frontend/src/shared/ui/Dialog.tsx frontend/src/shared/ui/Icon.tsx frontend/src/shared/ui/PagePlaceholder.tsx frontend/src/shared/ui/QueryState.tsx frontend/src/shared/ui/Select.tsx frontend/src/shared/useDebouncedValue.ts frontend/src/styles/tokens.css frontend/src/types/index.ts frontend/src/vite-env.d.ts frontend/tailwind.config.js frontend/tests/assistant-api.test.mjs frontend/tests/assistant.test.mjs frontend/tests/load-api.mjs frontend/tests/orders-api.test.mjs frontend/tests/orders.test.mjs frontend/tests/sales.test.mjs frontend/tests/settings.test.mjs frontend/tsconfig.app.json frontend/tsconfig.json frontend/tsconfig.node.json frontend/vite.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.