AAYMA
RU
Войти

Аким на 5 часов

Симулятор управления Астаной с интерактивной картой: пользователь выбирает 5 из 14 мер и районы в пределах бюджета 100 и получает Score, изменения…

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

О проекте

Команда: Название команды
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт

Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам

Суть

Симулятор управления Астаной с интерактивной картой: пользователь выбирает 5 из 14 мер и районы в пределах бюджета 100 и получает Score, изменения показателей и объяснение от AI. Есть советник, который подбирает лучший допустимый план.

Как устроено

FastAPI-эндпоинт /api/sim/evaluate проверяет правила (бюджет, ровно 5 мер, конфликты, лимиты направлений) и считает Score = 0.7·D_avg + 0.3·min(D) − N_crit с лагом (8−lag)/8 и синергиями. /api/sim/analyze передаёт проверенные факты LLM через OpenAI-совместимый API и стримит объяснение по SSE; числа подставляет сервер. Вклад мер оценивается по Шепли, optimizer.py ищет точный оптимум. Без ключа работает mock-режим.

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

  • Shapley values
  • exact plan optimizer
  • SSE streaming
  • deterministic scoring engine
  • MapLibre geo layers

Метрики

Пример жюри: Score 52.56 → 56.54 (+3.99), 95/100 бюджета, критические показатели 2 → 0; советник находит 57.24

Особенности

Вклад мер разложен по Шепли, модель только выбирает проверенные факты, а тексты и числа подставляет сервер. Настроен деплой с health-check и автооткатом.

Стек

Python · FastAPI · Pydantic · React 19 · TypeScript · Vite · Tailwind CSS 4 · MapLibre GL JS · nginx · systemd

Модели

OpenAI-compatible API (OPENAI_MODEL)


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

README

README.md

Аким на 5 часов — пять решений, один город, последствия на два года. Открыть живое демо.

AI-симулятор управления Астаной · кейс Astana Innovations
Изучите районы, распределите бюджет и узнайте последствия своих решений.

Открыть живое демо ↗   ·   Запустить локально   ·   Сценарий для жюри   ·   Техническое задание

Правила: ровно 5 разных решений из 14, бюджет 100 единиц, 5 расчётных районов, горизонт 8 кварталов.

Город оживает в ваших решениях

Школа в Нуре, чистое топливо в Сарыарке или цифровые сервисы для всего города? Ресурсов на всё не хватит. Соберите план, проверьте компромиссы и получите объяснение результата.

https://github.com/user-attachments/assets/c1c7dbb5-a679-4dec-a570-22b67309e630

25 секунд · 1080p · карта → план → результат. Ролик со звуком.

Приложение уже развёрнуто: hackalem.oqcrm.kz. Можно сразу открыть симулятор в браузере, без локальной установки.

Управлять — значит выбирать

01 · Изучите город02 · Соберите план03 · Поймите результат
Интерактивная карта, пять направлений и десять показателей каждого района. Найдите, где изменения нужнее всего.Выберите ровно пять разных мероприятий и назначьте районы. Проверяются бюджет, лимиты и несовместимости.Получите Score и изменения показателей. Аналитик объяснит сильные стороны, риски и компромиссы.

В рабочей версии:

  • Карта Астаны: выбор района, карточка показателей, плавная камера и пять независимых геослоёв.
  • План из 14 мероприятий: стоимость, лаг и ожидаемые эффекты видны до выбора; не больше двух мер из одного направления.
  • Проверка правил: бюджет до 100, ровно пять разных решений, обязательные районы и контроль конфликтов.
  • Прозрачный расчёт: показатели до и после, итоговый Score, критические значения и автоматически применённые синергии.
  • Аналитик: потоковое объяснение через OpenAI-совместимый API либо воспроизводимый отчёт без ключа.
  • Советник: точный подбор лучшего допустимого плана, сравнение с вашим сценарием и применение по кнопке.
  • Подсказки: пять шагов знакомства с интерфейсом по кнопке «Запустить подсказки».

Математика считает. ИИ объясняет

Все числа вычисляет детерминированный движок. Модель выбирает проверенные факты для объяснения; текст и числовые значения этих фактов подставляет сервер. Вклад отдельных мер оценивается по Шепли.

Score = 0.7 × D_avg + 0.3 × min(D) − N_crit
  • 70% веса — средний результат города с учётом долей населения.
  • 30% веса — самый слабый район: нельзя улучшить один район и забыть об остальных.
  • −1 балл за каждый показатель района строго ниже 40.

Эффект мероприятия учитывает срок начала действия: (8 − lag) / 8. Синергии добавляются отдельно, а итоговые показатели ограничиваются диапазоном 0–100. Остаток бюджета не даёт бонуса; порядок решений не влияет на результат.

Данные организаторов синтетические. Это учебная модель, а не актуальная статистика Астаны. Исходные значения и формула сохранены без изменений.

Формула и правила · Исходный датасет · Подробности расчёта

Проверить результат

Воспроизводимый сценарий для жюри — соберите эти пять мероприятий:

МераРешениеГде применяется
M7Школа + детсадНура
M8Центр семейного здоровья / поликлиникаНура
M10Освещение и камерыНура
M12Единая цифровая платформа обращенийВесь город
M5Перевод частного сектора на чистое топливоСарыарка

Нажмите «Рассчитать результат», затем «Объяснить результат».

Итоговый ScoreПотраченоОстатокКритические показатели
52,56 → 56,5495 / 10052 → 0

Прирост по точным значениям — +3,99. В Нуре обеспеченность школами меняется с 38 до 48, доступность медицины — с 35 до 43,75. Срабатывает синергия M10 + M12. Без ключа объяснение помечено как шаблонное и строится из рассчитанных данных.

Точные значения и полный сценарий проверки

Исходный Score: 52.55768. Итоговый: 56.54307. D_avg = 58.0776, min(D) = 52.9625, N_crit = 0. Округление применяется только для отображения.

Полный чеклист включает конфликты, смену района, геослои, карточки, подсказки, работу клавиатурой и экран шириной 360 px.

Проверить советника

  1. После расчёта примера выше со Score 56,54 нажмите «Подобрать лучший план».
  2. Сравните предложение с текущим планом: M2 и M14 — весь город; M3, M8 и M9 — Нура. Ожидаемый Score — 57,24 (точно 57.236735), стоимость — 98, критических показателей — 0.
  3. Нажмите «Применить предложенный план». Проверьте пять предложенных мер, остаток бюджета 2 и пересчитанный Score 57,24. До нажатия кнопки текущий план сохраняется.

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

Без API-ключа и без Docker. Нужны Git, uv, pnpm и Node.js. Проверено на Node.js 24; Vite требует ^20.19.0 || >=22.12.0. Python 3.13 и зависимости устанавливаются через uv при первом запуске.

Скрипт запускается в Bash на macOS / Linux. На Windows используйте WSL. Первый запуск требует сети для загрузки зависимостей; порты 8000 и 5173 должны быть свободны.

git clone https://github.com/BAITC-Hacks/hack-b4eba7e5-team.git
cd hack-b4eba7e5-team
LLM_MOCK=true ./dev.sh
АдресЧто открывает
127.0.0.1:5173Симулятор
127.0.0.1:8000/api/docsSwagger API
127.0.0.1:8000/api/healthСостояние бэкенда и режим аналитика

Для этого режима файл .env не нужен. Без заданного ключа mock включается автоматически: расчёт остаётся полноценным, аналитик выдаёт шаблонный отчёт. Остановка — Ctrl+C.

Подключить настоящего ИИ

Из корня репозитория создайте локальный файл настроек:

cp backend/.env.example backend/.env

Откройте backend/.env и заполните OPENAI_API_KEY=ваш-ключ.

ПеременнаяНазначение
OPENAI_API_KEYКлюч выбранного провайдера
OPENAI_MODELДоступная вашему ключу модель
OPENAI_FALLBACK_MODELЗапасная модель при временных ошибках
OPENAI_BASE_URLАдрес OpenAI-совместимого API; для обычного OpenAI не задаётся
LLM_MOCKtrue принудительно включает шаблонный режим даже при наличии ключа
LLM_CACHEtrue включает кеш ответов
AI_REQUESTS_PER_MINUTEОбщий лимит анализа и советника на процесс; по умолчанию 10

Выберите доступные вашему провайдеру модели. Убедитесь, что LLM_MOCK не включён в .env или окружении, и перезапустите приложение:

./dev.sh

Проверка подключения и доступных моделей:

cd backend
uv run python -m app.llm_check

Ключ хранится только на бэкенде. Файл .env исключён из Git; frontend .env для запуска не требуется.

Если приложение не запускается
  • uv или pnpm не найдены — установите инструменты по ссылкам выше и откройте новый терминал.
  • Vite сообщает об ошибке Node — проверьте node --version; используйте поддерживаемую версию, например 24.
  • Порт занят — остановите прежний локальный экземпляр и повторите запуск; frontend должен обращаться к тому же backend на 8000.
  • Аналитик пишет «Шаблон» после добавления ключа — проверьте LLM_MOCK и перезапустите ./dev.sh.
  • Нет подложки карты — внешние тайлы, шрифты и спрайты требуют сети. Выбор района остаётся доступен при отказе WebGL.

Под капотом

ИнтерфейсРасчётный движокОбъяснение
React 19 + TypeScriptFastAPI + Python 3.13OpenAI-совместимый API
Vite · Tailwind CSS v4 · MapLibre GL JS 5Pydantic v2 · проверка правил · фиксированный датасетOpenAI SDK · SSE · кеш · mock-режим
frontend → /api/sim/evaluate → проверка правил → расчёт → Score и показатели
frontend → /api/sim/analyze  → готовый результат → LLM / mock → объяснение SSE
backend/
  app/sim.py                Формулы, типы данных и валидатор
  app/optimizer.py          Точный подбор допустимого плана
  app/analysis.py           Проверенные факты и объяснение
  app/routes/sim.py         Конфигурация, расчёт и анализ
  app/llm.py                Единая обёртка вызовов модели
  .env.example             Шаблон настроек
  tests/                   Тесты без сети и API-ключа
  uv.lock                  Зафиксированные Python-зависимости
frontend/
  src/pages/               Экран симулятора
  src/components/          Карта, каталог и панели
  src/lib/api.ts           Запросы к бэкенду
  public/map/              Локальные геослои
  pnpm-lock.yaml           Зафиксированные frontend-зависимости
docs/                      Задание, датасет и документация
deploy/                    Скрипты выкатки и отката
dev.sh                     Локальный запуск backend + frontend

Продакшен работает на nginx + uvicorn под systemd. Docker и внешняя база данных для локального запуска не требуются.

API и эксплуатация · Данные карты · Правила разработки

Проверки

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

(cd backend && uv run pytest -q && uv run ruff check app tests && uv run ruff format --check app tests)
(cd frontend && node --test tests/*.test.mjs && pnpm lint && pnpm build)

Тесты проверяют формулу, бюджет, несовместимости, синергии, критический порог, API, потоковое объяснение и геоданные. Настоящий ключ и сеть для тестов не нужны. После изменений пройдите сценарий в браузере.

Что дальше

В планах — сохранение истории сценариев и агент с инструментами. Эти возможности пока не реализованы.

Продуктовые задачи · Архитектура


Какой будет ваша Астана? Откройте симулятор и примите пять решений →

HackAlem · кейс Astana Innovations. Карта: © OpenStreetMap contributors / ODbL; OpenFreeMap / OpenMapTiles. Источники геоданных.

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

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

Oryntai 21Oryntai 19Tokpoki 9Gdlllm 7Tokpoki 1

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

  • 2026-09-23 17:56Merge pull request #25 from BAITC-Hacks/codex/readme-advisor-checkOryntai
  • 2026-09-23 17:54Добавить сценарий проверки советника в READMEOryntai
  • 2026-09-23 17:43Оформить README в стиле приложения и добавить видеоOryntai
  • 2026-09-23 17:42Merge pull request #23 from BAITC-Hacks/codex/review-fixesOryntai
  • 2026-09-23 17:41Merge pull request #22 from BAITC-Hacks/gdlllm/collapsed-measuresOryntai
  • 2026-09-23 17:40Merge pull request #24 from BAITC-Hacks/codex/header-actionsOryntai
  • 2026-09-23 17:40Сворачивать мероприятия и переходить к итоговому ScoreGdlllm
  • 2026-09-23 17:39Убрать пустую строку над панелямиOryntai
Все коммиты (57)
  • 2026-09-23 17:39Добавить сравнение планов и защитить интерфейс от обрыва ответаOryntai
  • 2026-09-23 17:39Добавить точный оптимизатор и проверенный анализ сценариевOryntai
  • 2026-09-23 17:35Merge pull request #21 from BAITC-Hacks/codex/remove-simulator-labelOryntai
  • 2026-09-23 17:35Убрать подпись и выделить доступный сброс планаOryntai
  • 2026-09-23 17:31Merge pull request #19 from BAITC-Hacks/codex/panel-spacingOryntai
  • 2026-09-23 17:30Сбалансировать отступы вокруг панелейOryntai
  • 2026-09-23 17:25Merge pull request #18 from BAITC-Hacks/codex/compact-simulator-headerOryntai
  • 2026-09-23 17:24Убрать лишний текст над картойOryntai
  • 2026-09-23 17:21Merge pull request #17 from BAITC-Hacks/gdlllm/scroll-panelsOryntai
  • 2026-09-23 17:21Разделить карту и план на панели с независимой прокруткойGdlllm
  • 2026-09-23 17:09Герб Астаны в шапке сайта (#16)Tokpoki
  • 2026-09-23 17:07Герб Астаны в шапке сайтаTokpoki
  • 2026-09-23 17:05Merge pull request #15 from BAITC-Hacks/codex/tour-help-buttonOryntai
  • 2026-09-23 17:04Круглая кнопка запуска подсказокOryntai
  • 2026-09-23 16:57Merge pull request #13 from BAITC-Hacks/gdlllm/map-popup-cornerOryntai
  • 2026-09-23 16:54Merge pull request #14 from BAITC-Hacks/codex/tour-finish-scrollOryntai
  • 2026-09-23 16:53Плавный возврат после завершения подсказокOryntai
  • 2026-09-23 16:49Закрепить попап района в углу карты и уменьшить на 15%Gdlllm
  • 2026-09-23 16:37Изменяемая ширина каталога и плавная карта (#12)Tokpoki
  • 2026-09-23 16:36Изменяемая ширина каталога и плавное масштабирование картыTokpoki
  • 2026-09-23 16:25Вернуть плавный скролл в подсказках (#11)Oryntai
  • 2026-09-23 16:24Вернуть плавную прокрутку между подсказкамиOryntai
  • 2026-09-23 16:20Стабильные подсказки и собственный выбор районов (#10)Oryntai
  • 2026-09-23 16:20Добавить единый список выбора районовOryntai
  • 2026-09-23 16:14Зафиксировать подсказки и убрать рывки между шагамиOryntai
  • 2026-09-23 16:12Добавить попапы районов и подробную статистику (#9)Gdlllm
  • 2026-09-23 16:10Карточки районов на карте и пояснения мероприятийGdlllm
  • 2026-09-23 16:10Уточнить проверки diff и конфликтов перед отправкойGdlllm
  • 2026-09-23 16:09Предпросмотр эффектов мероприятий с учётом лаговGdlllm
  • 2026-09-23 16:04Добавить подсказки с ручным запуском (#8)Oryntai
  • 2026-09-23 16:03Добавить плавные подсказки с ручным запускомOryntai
  • 2026-09-23 15:56Убрать кнопку готового примера (#7)Tokpoki
  • 2026-09-23 15:55Убрать кнопку готового примера из симулятораTokpoki
  • 2026-09-23 15:50Улучшить карту и убрать лишние надписиOryntai
  • 2026-09-23 15:49Увеличить карту и добавить независимые цветные слоиOryntai
  • 2026-09-23 15:47Добавить анимацию оценки города и искры (#5)Tokpoki
  • 2026-09-23 15:45Анимация оценки города с цветной шкалой и искрамиTokpoki
  • 2026-09-23 15:29Объединить Алматы и Сарайшык и упростить оформлениеOryntai
  • 2026-09-23 15:28Объединить Алматы и Сарайшык и упростить оформлениеOryntai
  • 2026-09-23 15:14Добавлена карта Астаны с плавным выбором районаOryntai
  • 2026-09-23 15:13Карта Астаны с точным выбором района и плавным интерфейсомOryntai
  • 2026-09-23 14:49Добавлен рабочий MVP симулятора городаOryntai
  • 2026-09-23 14:48Рабочий прототип симулятора города с расчётом и аналитикомOryntai
  • 2026-09-23 14:15Каркас приложения: FastAPI + React, обёртка над OpenAI со стримингомOryntai
  • 2026-09-23 14:15Деплой: релизы с health-check и автооткатом, секреты и логиOryntai
  • 2026-09-23 14:15ТЗ кейса, данные в JSON и согласованная архитектураOryntai
  • 2026-09-23 14:15README проекта и правила разработки командыOryntai
  • 2026-09-23 13:53Merge pull request #1 from BAITC-Hacks/tokpoki/add-case-docsTokpoki
  • 2026-09-23 13:50Добавить материалы кейсаTokpoki
Структура репозитория (103 файлов)
.gitignore
AGENTS.md
CLAUDE.md
HackAlem AI_ «Аким на 5 часов» - AI-симулятор управления городом.docx
README.md
backend/.env.example
backend/.python-version
backend/app/__init__.py
backend/app/analysis.py
backend/app/config.py
backend/app/data/dataset.json
backend/app/llm.py
backend/app/llm_check.py
backend/app/logs.py
backend/app/main.py
backend/app/optimizer.py
backend/app/rate_limit.py
backend/app/routes/__init__.py
backend/app/routes/chat.py
backend/app/routes/sim.py
backend/app/sim.py
backend/app/sse.py
backend/pyproject.toml
backend/tests/conftest.py
backend/tests/test_advisor.py
backend/tests/test_llm.py
backend/tests/test_map_data.py
backend/tests/test_sim.py
backend/tests/test_smoke.py
backend/uv.lock
deploy/config.sh
deploy/deploy.sh
deploy/hackalem.service
deploy/llm-check.sh
deploy/logs.sh
deploy/nginx.conf
deploy/rollback.sh
deploy/server-bootstrap.sh
deploy/set-secret.sh
dev.sh
docs/ARCHITECTURE.md
docs/DEMO.md
docs/MAP_DATA.md
docs/REFERENCE.md
docs/TASKS.md
docs/TZ.md
docs/assets/README.md
docs/assets/cover.svg
docs/assets/rules.svg
docs/dataset.json
frontend/.gitignore
frontend/.oxlintrc.json
frontend/index.html
frontend/package.json
frontend/pnpm-lock.yaml
frontend/public/astana-emblem.LICENSE.txt
frontend/public/astana-emblem.svg
frontend/public/favicon.svg
frontend/public/map/green_spaces.json
frontend/public/map/healthcare.json
frontend/public/map/road_safety_objects.json
frontend/public/map/schools_kindergartens.json
frontend/public/map/transport_stops.json
frontend/src/App.tsx
frontend/src/ErrorBoundary.tsx
frontend/src/components/.gitkeep
frontend/src/components/AstanaMap.tsx
frontend/src/components/DistrictPopup.tsx
frontend/src/components/DistrictSelect.tsx
frontend/src/components/GuidedTour.tsx
frontend/src/components/MeasureDetails.tsx
frontend/src/components/PlanAdvisor.tsx
frontend/src/components/ResizableColumns.tsx
frontend/src/components/ScoreGauge.tsx
frontend/src/data/basemap.json
frontend/src/data/districts.json
frontend/src/index.css
frontend/src/lib/api.ts
frontend/src/lib/districtSelectLayout.ts
frontend/src/lib/districts.ts
frontend/src/lib/mapViewport.ts
frontend/src/lib/panelClasses.ts
frontend/src/lib/panels.ts
frontend/src/lib/score.ts
frontend/src/lib/scrollPanel.ts
frontend/src/lib/tour.ts
frontend/src/main.tsx
frontend/src/pages/ChatPage.tsx
frontend/src/pages/SimulatorPage.tsx
frontend/tests/districtSelectLayout.test.mjs
frontend/tests/mapViewport.test.mjs
frontend/tests/panels.test.mjs
frontend/tests/score-preview.html
frontend/tests/score-preview.tsx
frontend/tests/score.test.mjs
frontend/tests/scrollPanel.test.mjs
frontend/tests/streamIntegrity.test.mjs
frontend/tests/tour.test.mjs
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
Датасет районов.docx

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

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

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