AAYMA
RU
Войти

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

AI-симулятор управления Астаной с интерактивной SVG-картой 5 районов и 14 мер.

Доведённый продукт
Команда «BOM КазАЙ» 4💬 0 комментариевс 22 сентября 2026 г.

О проекте

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

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

Суть

AI-симулятор управления Астаной с интерактивной SVG-картой 5 районов и 14 мер. Считает Astana Quality of Life Score на горизонте 8 кварталов, по запросу выдаёт AI-рекомендации на трёх языках (ru/kk/en).

Как устроено

Данные лежат в versioned JSON (tech2-v1: районы, меры, правила). Python-ядро на FastAPI проверяет бюджет, конфликты и лимит «не более двух мер на направление» и считает результат по формуле: эффект × (8 − задержка)/8, баллы районов с весами индикаторов, взвешивание по населению, Score = 0,7·среднее + 0,3·минимум − N критических показателей. Браузерная JS-модель показывает предпросмотр, её совпадение с API проверяет parity-тест. По кнопке OpenAI Responses API пишет объяснение по фактам отчёта; ответ кешируется, при ошибке включается fallback.

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

  • deterministic scoring formula
  • synergies/conflicts rules
  • delayed effects
  • browser/API parity test
  • OpenAI Responses structured output
  • fallback explanations
  • i18n ru/kk/en

Особенности

Расчёт продублирован в браузере и на сервере, их совпадение проверяет отдельный parity-тест. Формула скоринга опубликована и отдельно учитывает самый слабый район. Автотестов 70 (41 JS и 29 Python); AI вызывается только по кнопке и кешируется по сценарию, языку и району.

Стек

Python 3.12 · FastAPI · Uvicorn · Pydantic v2 · Node.js 22 · vanilla JS/SVG · Docker Compose

Модели

gpt-6-luna (OpenAI Responses API)


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

README

README.md

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

AI-симулятор управления Астаной: распределите бюджет 100 условных единиц между пятью инициативами и получите Astana Quality of Life Score с объяснением последствий.

Проект предназначен для городских управленцев, аналитиков и участников симуляции. Он позволяет сравнить, как решения в транспорте, экологии, социальной инфраструктуре, безопасности и городских сервисах влияют на качество жизни. Все начинают с одинаковых синтетических данных.

Возможности

  • Интерактивная карта пяти районов и 14 мероприятий с заданными стоимостью и эффектами.
  • Контроль бюджета, количества решений и совместимости мер.
  • Предварительный просмотр изменений и итоговый отчёт по городу и районам на горизонте восьми кварталов.
  • Краткие AI-рекомендации по запросу для города или выбранного района.
  • Интерфейс и объяснения на русском, казахском и английском.

Запуск

Нужны Git и Docker с Compose. Команды для Bash:

git clone https://github.com/BAITC-Hacks/hack-518b6a53-bom.git
cd hack-518b6a53-bom
test -f .env.local || cp .env.example .env.local
docker compose --env-file .env.local up -d --build

Откройте http://localhost:4173. Публичной демоверсии пока нет.

Для AI-разбора заполните в .env.local оба поля: OPENAI_API_KEY и OPENAI_MODEL — ключ и доступный API ID модели с поддержкой структурированных ответов Responses API. Модель по умолчанию не задана; текущая интеграция проверена с gpt-6-luna. После изменения настроек повторите команду запуска. Обычный расчётный отчёт доступен сразу, AI вызывается только кнопкой «Получить рекомендации ИИ». Без конфигурации AI или при ошибке OpenAI приложение сохраняет обычный отчёт и показывает сообщение о недоступности рекомендаций. Ключ не добавляйте в Git.

Остановка:

docker compose --env-file .env.local down

Если приложение не отвечает, проверьте логи:

docker compose --env-file .env.local logs --tail=100 ui api

Остальные параметры окружения описаны в .env.example.

Пример использования

Выберите карточку мероприятия и нажмите на нужный район либо перетащите её на карту. Городская мера применяется ко всему городу. Соберите такой план:

IDМероприятиеГдеСтоимость
M7Школа + детсадНура24
M8Центр семейного здоровьяНура20
M10Освещение и камеры Safe CityНура12
M12Платформа обращений жителейВесь город14
M5Чистое топливо для частного сектораСарыарка25

Нажмите «Рассчитать». Стоимость — 95 из 100, Score меняется с 52,56 до 56,54. В отчёте доступны показатели и выводы по городу и районам. Нажмите «К карте», чтобы изменить план, или «Новый сценарий», чтобы начать заново.

По умолчанию показывается обычный отчёт с числовыми результатами и шаблонными выводами. Для AI выберите вкладку города или любого района и нажмите «Получить рекомендации ИИ»: появится короткий абзац на текущем языке интерфейса. Открытие отчёта, смена района и языка не запускают AI автоматически. Полученный ответ кешируется для текущего сценария, языка и района; к обычному отчёту можно вернуться отдельной кнопкой. Изменение плана сбрасывает эти ответы.

Для проверки поведения:

  • Замените M10 на M11 в Нуре: стоимость станет 93, Score — 56,33.
  • Вместо M10 попробуйте добавить M3: стоимость превысила бы бюджет до 113, поэтому добавление будет отклонено.
  • Удалите одну меру: расчёт недоступен, пока в плане не будет пяти допустимых решений.

Правила и расчёт

Нужно выбрать ровно пять разных мероприятий, не более двух одного направления, на сумму до 100. Выбор по одному мероприятию из каждого направления не требуется. M1 и M3 несовместимы; M4 и M7, а также M5 и M13 нельзя сочетать в одном районе.

У каждого района десять индикаторов от 0 до 100 — больше означает лучше. Эффекты мер учитывают задержку реализации и совместное действие некоторых инициатив. После их применения значения индикаторов ограничиваются диапазоном 0–100.

Эффект меры = эффект из каталога × (8 − задержка в кварталах) / 8
Балл района = сумма значений индикаторов с их весами
Средний балл = сумма баллов районов с весами по доле населения
Score = 0,7 × средний балл + 0,3 × минимальный балл района − N

N — количество пар «район — индикатор» со значением ниже 40. Формула учитывает средний уровень города, слабейший район и критические показатели. Веса, конфликты и синергии заданы в rules.json.

Технологии и архитектура

flowchart LR
    Browser["Браузер: HTML, CSS, JavaScript, SVG"] <-->|":4173"| UI["Node.js: статика и прокси"]
    UI <-->|":8000"| API["Python / FastAPI: проверка и расчёт"]
    Data["JSON-датасет"] --> API
    API <-->|"Факты / объяснение"| AI["OpenAI Responses API"]

Интерфейс работает без UI-фреймворка и npm-зависимостей. Браузерная модель показывает предварительные изменения; итоговый результат проверяет и рассчитывает Python. OpenAI получает факты отчёта и формирует объяснение. Числа в отчёте определяет расчётная модель.

В Docker используются Node.js 22 и Python 3.12. Backend — FastAPI, Uvicorn, Pydantic v2 и OpenAI SDK; версии закреплены в requirements/api.lock. Compose публикует только интерфейс на 127.0.0.1:4173, API доступен внутри сети контейнеров. Ключ OpenAI хранится на стороне API.

API предоставляет каталог, проверку сценария, расчёт и объяснение. Маршруты и форматы запросов описаны в контракте backend. Ответ объяснения содержит mode: "llm" или mode: "fallback".

Структура проекта:

frontend/       HTML, CSS, JavaScript, SVG, package.json, Node-сервер и JS-тесты
backend/        FastAPI, расчётное ядро, валидация и AI-адаптер
shared/         Схемы HTTP-запросов и ответов
data/tech2-v1/  Версионированные исходные данные и правила
docker/         Dockerfile интерфейса и API
docs/           Контракты и документация
tests/          Python-тесты и сверка браузерного расчёта с API
requirements/   Зафиксированные зависимости Python
compose.yaml    Запуск интерфейса и API

Данные и ограничения

Датасет data/tech2-v1 содержит пять районов — Есиль, Алматы, Сарыарка, Байконур и Нура, — их показатели, доли населения, мероприятия и правила. Данные синтетические; персональные данные не нужны.

  • Результат показывает поведение условной модели и не является проверенным прогнозом развития города.
  • Живых городских данных и подключений к городским системам нет. Единственная внешняя интеграция — OpenAI для объяснений.
  • Карта схематична и основана на расположении районов 2023 года; текущие юридические границы не воспроизводятся.
  • Нет авторизации и сохранения сценариев: перезагрузка страницы сбрасывает план. Сохраняется только язык интерфейса.
  • Сравнение команд, случайные события и генерация презентаций не реализованы.

Разработка и тесты

Запуск с подключёнными исходниками и автоматической перезагрузкой серверов:

docker compose --env-file .env.local -f compose.yaml -f compose.dev.yaml up -d --build

Интерфейс остаётся на порту 4173, API — на порту 8000. Документация Swagger UI доступна на http://localhost:8000/docs. Для остановки используйте те же Compose-файлы с командой down.

Все тесты можно запустить в Docker без Node.js и Python на хосте. Команды из корня проекта используют актуальные исходники; ответы OpenAI подменяются, платных API-вызовов нет:

docker compose --env-file .env.local build ui api
docker compose --env-file .env.local run --rm --no-deps -v .:/workspace:ro -w /workspace/frontend ui npm test
docker compose --env-file .env.local -f compose.yaml -f compose.dev.yaml run --rm --no-deps -v ./tests:/app/tests:ro api python -m unittest discover -s tests -p test_backend.py -v

Проходят 41 JavaScript-тест и 29 Python-тестов: расчёты и ограничения, переводы, API-контракты, полнота рассчитанных вкладов и дельт в AI-контексте, область AI-объяснения, fallback и отмена запроса при отключении клиента.

Для сверки браузерной модели с работающим API сначала выполните обычную команду запуска из раздела «Запуск», затем:

docker compose --env-file .env.local run --rm --no-deps -v .:/workspace:ro -w /workspace ui node tests/parity.mjs http://ui:4173

При установленном Node.js ≥ 22 те же JavaScript-проверки доступны локально через npm --prefix frontend test, а сверка с запущенным приложением — через node tests/parity.mjs или npm --prefix frontend run test:parity. Установка npm-пакетов не требуется.

Материалы

ТЗ и критерии оценки — Данные и правила кейса — Требования к README.

Исходные материалы: ТЗ в Google Docs и датасет в Google Docs.

Геометрия в frontend/map-geometry.js адаптирована по Astana districts coloured 2023.png, автор Bogomolov.PL, лицензия CC BY-SA 4.0. Уведомление относится только к геометрии карты.

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

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

David Dolya 20Ilya Molokovich 9Дмитрий 5

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

  • 2026-09-23 17:56Remove obsolete architecture draft and dbarin test fileIlya Molokovich
  • 2026-09-23 17:53Complete AI calculation context and correct architecture documentationIlya Molokovich
  • 2026-09-23 17:42Merge main documentation and organize frontend with verified Docker startupIlya Molokovich
  • 2026-09-23 17:37Merge latest dbarin frontend and add on-demand scoped AI recommendationsIlya Molokovich
  • 2026-09-23 17:35readme mostly completed'David Dolya
  • 2026-09-23 17:24Добавил адаптивный интерфейс, объяснения результатов и карточки объектовДмитрий
  • 2026-09-23 17:18Verify MVP integration and improve responsive map and report behaviorIlya Molokovich
  • 2026-09-23 17:03Connect MVP widget to FastAPI and localized OpenAI reportsIlya Molokovich
Все коммиты (34)
  • 2026-09-23 16:55Merge david backend with latest dbarin frontend for MVPIlya Molokovich
  • 2026-09-23 16:54Обновил дизайн и расположение переключателя языковДмитрий
  • 2026-09-23 16:33Добавить интерактивный симулятор развития АстаныДмитрий
  • 2026-09-23 16:19added technical file 1 in a proper .md formatDavid Dolya
  • 2026-09-23 16:12README clean upDavid Dolya
  • 2026-09-23 16:11Fix backend validation, HTTP errors and loggingDavid Dolya
  • 2026-09-23 15:44backend stage 8: doneDavid Dolya
  • 2026-09-23 15:38Handle malformed OpenAI explanation responsesDavid Dolya
  • 2026-09-23 15:35backend stage 7: ver 1David Dolya
  • 2026-09-23 15:31backend stage 6: ver 1David Dolya
  • 2026-09-23 15:28Fix nested selection serialization in API responsesDavid Dolya
  • 2026-09-23 15:25backend stage 5: ver 1David Dolya
  • 2026-09-23 15:21backend stage 4: ver 1David Dolya
  • 2026-09-23 15:18Fix budget totals for unknown district IDsDavid Dolya
  • 2026-09-23 15:17Reshape simulator as a viewport-sized map widgetIlya Molokovich
  • 2026-09-23 15:13backend stage 3: version 1David Dolya
  • 2026-09-23 15:09backend stage 2: doneDavid Dolya
  • 2026-09-23 15:05Add Astana city planning frontend demoIlya Molokovich
  • 2026-09-23 15:01Fix city selection serializationDavid Dolya
  • 2026-09-23 15:00backend stage 1: version 1 of project structure, primaraly backend partDavid Dolya
  • 2026-09-23 14:53Добавил иллюстрации страниц и PNG-логотип в казахском стилеДмитрий
  • 2026-09-23 14:50a sequence of prompts for backend agents is doneDavid Dolya
  • 2026-09-23 14:30second version of architecture addedDavid Dolya
  • 2026-09-23 14:17first neuroslop for project architectureDavid Dolya
  • 2026-09-23 14:17added technical requirements to data.mdDavid Dolya
  • 2026-09-22 12:16Тест dbarinДмитрий
Структура репозитория (76 файлов)
.dockerignore
.env.example
.gitignore
ARCHITECTURE_PYTHON_DOCKER.md
README.md
assets/images/astana-kazakh-hero.png
assets/images/initiatives-kazakh.png
assets/images/logo-akim.png
assets/images/method-kazakh.png
assets/images/plan-kazakh.png
assets/images/results-kazakh.png
backend/__init__.py
backend/adapters/__init__.py
backend/adapters/dataset.py
backend/adapters/fallback.py
backend/adapters/llm.py
backend/domain/__init__.py
backend/domain/models.py
backend/domain/report.py
backend/domain/simulation.py
backend/domain/validation.py
backend/main.py
backend/prompts/.gitkeep
backend/prompts/explanation.txt
backend/routes.py
backend/services/__init__.py
backend/services/explanation_context.py
backend/services/explanations.py
backend/services/scenarios.py
backend/settings.py
compose.dev.yaml
compose.yaml
data.md
data/tech2-v1/districts.json
data/tech2-v1/measures.json
data/tech2-v1/presets.json
data/tech2-v1/rules.json
data_2_1.md
docker/api.Dockerfile
docker/ui.Dockerfile
docs/BACKEND_AGENT_PROMPTS.md
docs/BACKEND_CONTRACT.md
docs/IMPLEMENTATION_LOG.md
docs/INTEGRATION_CHECKS.md
docs/README_PROMPT_EXAMPLE.md
frontend/api.js
frontend/api.test.js
frontend/app.js
frontend/i18n.js
frontend/i18n.test.js
frontend/index.html
frontend/locales.js
frontend/map-geometry.js
frontend/map-object-art.js
frontend/map-objects.js
frontend/map-objects.test.js
frontend/model.js
frontend/model.test.js
frontend/package.json
frontend/server.js
frontend/server.test.js
frontend/styles.css
frontend/svg/all.svg
frontend/svg/city.svg
frontend/svg/district.svg
frontend/svg/ecology.svg
frontend/svg/security.svg
frontend/svg/services.svg
frontend/svg/social.svg
frontend/svg/transport.svg
requirements/api.in
requirements/api.lock
shared/__init__.py
shared/schemas.py
tests/parity.mjs
tests/test_backend.py
Ветки (5)

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

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

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