AAYMA
RU
Войти

Аким на 5 часов — Astana City Control

Городской симулятор: игрок на интерактивной карте Астаны выбирает меры в пределах бюджета 100 у.е., серверный движок считает последствия для 5…

Доведённый продукт
Команда «K-On!» 4💬 0 комментариевс 23 сентября 2026 г.

О проекте

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

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

Суть

Городской симулятор: игрок на интерактивной карте Астаны выбирает меры в пределах бюджета 100 у.е., серверный движок считает последствия для 5 районов по 10 показателям за 8 кварталов, AI-советник объясняет результат.

Как устроено

Каталог мер и правил хранится в JSON. Python-движок в Django API считает баллы, бюджет, синергии и конфликты, задержки эффектов, критические пороги и изменения против исходного состояния. React/TypeScript-интерфейс показывает карту проблем, план, переключатель «До/После» и таблицу районов. AI-советник (OpenAI Responses API со структурированным JSON) получает доверенный результат движка и ведёт диалог с серверной историей. Режим demo работает без ключа и помечен явно.

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

  • расчётный движок с синергиями и конфликтами мер
  • отложенные эффекты
  • учёт слабейшего района и критических порогов
  • структурированный JSON-ответ LLM
  • серверная история чата

Метрики

Контрольный план: общий балл 52.6151 → 56.5697, критических показателей 2 → 0, стоимость 95 из 100

Особенности

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

Стек

Python · Django · React · TypeScript · Vite · SQLite · Node.js

Модели

OpenAI (Responses API)


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

README

README.md

Аким на 5 часов — Astana City Control

Учебный симулятор городских решений с интерактивной картой, расчётным движком и AI-советником. Проект команды K-On! для спецтрека Astana Innovations.

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

5 районов · 10 показателей · 14 мер · бюджет 100 условных единиц · горизонт 8 кварталов.

Интерфейс проекта: карта районов, проблемы города и план решений

Запуск · Сценарий проверки · Архитектура · Роль AI · Тесты · Ограничения

Задача и ценность

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

Симулятор подходит для учебных занятий, командных обсуждений и демонстрации принципов распределения ресурсов. Игрок видит, почему нужно учитывать не только общий результат, но и слабейший район и критические дефициты. Применение для реального муниципального планирования потребует актуальных данных и проверки модели; такая проверка пока не проводилась.

Что реализовано

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

Окно проблемы с показателем 38, порогом 40 и подходящими мерами

Проверка по критериям хакатона

КритерийВесЧто предъявляет проектКак проверить
Соответствие задаче и работоспособность25Полный сценарий от проблемы района до расчёта плана и объяснения результатаПройти демонстрационный сценарий и сравнить числа
Техническая реализация25React-интерфейс, Django API, независимый расчётный движок, адаптер AI, серверные сессии и валидацияИзучить архитектуру, роль AI и запустить тесты
README и воспроизводимость25Запуск с чистого клона, режим без ключа, контрольный план, ожидаемые результаты и команды проверкиВыполнить инструкцию запуска и проверки
Ценность и применимость15Наглядное изучение бюджетных ограничений, отложенных эффектов и неравномерности развития районовСравнить исходное состояние и результат, обсудить сценарии применения
Потенциал развития и оригинальность подхода10Связка карты проблем, проверяемого расчёта и объяснения; учёт слабейшего района и критических дефицитовОзнакомиться с направлениями развития и обозначенными ограничениями

Вес критериев приведён из условий оценки; таблица показывает материалы для проверки, а не присваивает проекту баллы.

Запуск с чистого клона

Требования

КомпонентТребование
Python3.12 или новее; проверено на 3.14.4
Node.js22.18 или новее; проверено на 24.21.0
npm и GitДля установки зависимостей и получения репозитория
ИнтернетДля клонирования и установки зависимостей; для настоящего AI — также во время работы

SQLite используется как локальная база данных; отдельный сервер БД не нужен. После установки зависимостей режим demo работает без внешнего AI-сервиса. Каталоги .venv, node_modules, .tools и файл .env не входят в репозиторий — их наличие на компьютере автора не требуется для запуска.

Команды ниже рассчитаны на Linux/macOS. В Windows можно использовать WSL либо запускать backend и frontend в отдельных терминалах, активировав окружение через .venv\Scripts\Activate.ps1.

1. Получить код и установить зависимости

git clone https://github.com/BAITC-Hacks/hack-1ce365d5-k-on.git
cd hack-1ce365d5-k-on

git switch main
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
npm ci

Для закрытого репозитория нужен доступ к нему в GitHub. Версии Python-зависимостей закреплены в requirements.txt, JavaScript-зависимостей — в package-lock.json.

2. Подготовить окружение и базу

В новом клоне создайте .env из примера:

cp .env.example .env
python manage.py migrate

Если .env уже существует, сохраните его настройки. Для первого запуска измените в нём одну строку:

AKIM_AI_PROVIDER=demo

Django автоматически читает .env. Переменные, уже заданные в окружении процесса, имеют приоритет. Каталог и настоящий расчётный движок подключены по умолчанию; API-ключ для них не требуется.

3. Запустить два процесса

В первом терминале, с активированным .venv:

python manage.py runserver 127.0.0.1:8000

Во втором терминале, из корня проекта:

npm run dev -- --host 127.0.0.1

Откройте http://127.0.0.1:5173 — или адрес, напечатанный Vite, если порт занят. Интерфейс работает через Vite; Django на порту 8000 обслуживает /api, а не главную страницу приложения.

После установки зависимостей на Linux с Bash 4.3+ оба процесса можно запускать одной командой:

./scripts/dev.sh

Скрипт применяет миграции при запуске нового backend, учитывает DJANGO_API_TARGET и может использовать уже работающий Django. Ctrl+C останавливает процессы, запущенные самим скриптом. Если backend был запущен отдельно, его нужно остановить отдельно.

4. Подключить настоящий AI

Для настоящих ответов замените настройки в .env и перезапустите Django:

AKIM_AI_PROVIDER=openai
OPENAI_API_KEY=<ваш_API_ключ>
OPENAI_MODEL=<идентификатор_доступной_вам_модели>

Адаптер использует OpenAI Responses API со структурированным JSON-ответом. Нужна модель с поддержкой этого формата; конкретная модель автоматически не выбирается. Ключ остаётся на сервере и не должен попадать в Git или переменные с префиксом VITE_. Запросы к внешнему сервису могут тарифицироваться провайдером.

Режим demo — заранее написанный пример ответа, а не языковая модель. Он нужен для проверки интерфейса и передачи данных. Его текст общий и не интерпретирует конкретный расчёт; числовые результаты в этом режиме всё равно вычисляет настоящий Python-движок. Интерфейс помечает такие ответы как «ДЕМО».

Демонстрационный сценарий

Сценарий проверяется без ключа, с AKIM_AI_PROVIDER=demo. Настоящий AI можно включить отдельно для оценки качества объяснений.

  1. Откройте карту. В Нуре отмечены две критические проблемы: школы и детсады — 38, поликлиники — 35 при пороге 40.
  2. Нажмите на значок школы или больницы. Проверьте значение, описание и список мер. «Подобрать меры» открывает каталог с фильтром по проблеме.
  3. Сбросьте фильтр проблемы крестиком, оставьте «Все направления» и соберите план из таблицы. Для первых трёх мер выберите район Нура. Для городской меры район не нужен. Перед добавлением M5 выберите Сарыарку.
  4. Нажмите «Запустить симуляцию». Проверьте балл, бюджет и число критических показателей в разделе «Прогноз развития».
  5. Переключите карту между «До решений» и «После расчёта». После расчёта обе критические отметки Нуры исчезают. Раскройте таблицу показателей районов для проверки изменений.
  6. В режиме настоящего AI спросите: «Какие слабые места остались у этого плана?» Измените одну меру: интерфейс отметит, что показанный результат относится к предыдущему расчёту. Запустите симуляцию повторно для нового результата.

В карточках интерфейса используются названия мер; ID ниже нужны для сопоставления с API и каталогом.

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

Ожидаемый результат для включённого каталога:

ПоказательДо решенийПосле расчёта
Общий балл52.615156.5697
Критические показатели20
Школы и детсады Нуры, S13848
Поликлиники Нуры, S23543.75

Стоимость плана — 95, остаток — 5, прирост балла — 3.9546. Интерфейс округляет балл до 56,57, прирост — до +3,95. Это контрольный пример, а не утверждение об оптимальном плане.

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

flowchart LR
    UI[React + TypeScript: карта, план, чат] -->|относительные /api запросы| Vite[Vite: proxy]
    Vite --> API[Django: JSON API и CSRF]
    API --> Engine[Python: расчётный движок]
    Catalog[JSON-каталог: данные и правила] --> Engine
    Catalog --> Advisor[Advisor: контекст и проверка ответа]
    Engine -->|доверенный результат| API
    API <-->|история и последний расчёт| DB[(SQLite: Django sessions)]
    API --> Advisor
    Advisor --> Model[OpenAI API или DemoModel]
    Model --> Advisor
    Advisor -->|объяснение| API
    API -->|результат и ответ| UI
КомпонентРеализация и ответственность
ИнтерфейсReact 19, TypeScript 6, Vite 8; React hooks для состояния, SVG-карта и Lucide для иконок
APIDjango 6.1.1; чтение JSON, проверка полей/ID, вызов движка и советника, согласованные ошибки
РасчётОтдельный Python-модуль без зависимости от LLM; эффект мер, правила, синергии, баллы и исходное состояние
AIakim_ai.Advisor, шаблоны инструкций, JSON Schema и сменный адаптер модели
ДанныеВерсионируемый JSON-каталог с районами, индикаторами, мерами и правилами
Состояние игрокаАнонимная cookie-сессия Django; последний расчёт и до 20 успешных пар сообщений в SQLite
ПроверкиDjango/unittest, встроенный тестовый раннер Node.js, TypeScript и Oxlint

Взаимодействие компонентов

МаршрутНазначение
GET /api/catalogВозвращает каталог и устанавливает CSRF-cookie
POST /api/simulateПринимает пять пар measure_id / district_id, считает результат и запрашивает объяснение
POST /api/advisor/chatПринимает только message; история и доверенный результат берутся из серверной сессии

Для общегородской меры передаётся district_id: null. Браузер не может передать свой Score как результат движка. Клиентская проверка помогает игроку собрать план, а обязательная серверная проверка защищает расчёт от некорректных запросов.

Vite проксирует /api в Django с сохранением пары Host/Origin; запросы используют cookie и CSRF-токен. В интерфейсе одновременно выполняется не более одного запроса симуляции или чата. Успешная новая симуляция начинает новый диалог; ошибка движка сохраняет предыдущий расчёт. При ошибке AI уже полученный результат движка остаётся доступен.

Форматы запросов, ответов и ошибок: контракт API.

Расчётная модель

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

Эффект меры к концу горизонта:

реализованный эффект = полный эффект × (8 − задержка) / 8
Score = 0.7 × средний балл с весами населения
      + 0.3 × минимальный балл района
      − число критических показателей

Баллы районов — средние десяти индикаторов. Критическим считается каждое значение строго ниже 40. Синергии применяются один раз, итоговые индикаторы ограничиваются диапазоном 0–100, остаток бюджета не даёт бонуса. Порядок добавления мер не меняет результат.

Равные веса индикаторов внутри района, ограничение значений после суммирования эффектов и применение синергий без дополнительной задержки — явно принятые допущения. Формулы, подробности и числовые тесты описаны в документации движка.

Как используется AI

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

LLM формирует структурированный брифинг: краткое объяснение, сильные стороны, риски и следующий шаг. Код проверяет JSON-структуру и существование ссылок evidence_ids, после чего преобразует брифинг в текст для интерфейса. Модель не рассчитывает баллы и не применяет решения за игрока. Проверка ссылок на факты не гарантирует смысловую точность каждого утверждения — качество текста требует отдельной оценки.

В библиотеке есть ограниченный агентный сценарий с suggest=true: модель предлагает до трёх наборов, код проверяет их состав, а при переданном серверном симуляторе рассчитывает допустимые варианты и возвращает результаты модели для объяснения. Этот подбор кандидатов пока не подключён к веб-интерфейсу. CLI без переданного симулятора помечает предложения как unverified. Здесь используется управляемая программой последовательность вызовов, а не нативный function calling провайдера.

Примеры независимого запуска библиотеки без API-ключа:

python -m akim_ai --provider demo --input examples/request.json
python -m akim_ai --provider demo --input examples/plan.json

CLI читает переменные процесса и не загружает .env; Django загружает его автоматически. Подробнее: руководство Advisor.

Проверка решения

Из корня проекта, с активированным Python-окружением:

python manage.py check
python manage.py test
npm test
npm run lint
npm run build

При подготовке этой документации прошли 71 backend-тест и 13 frontend-тестов, проверка типов, lint и production-сборка. Автоматические тесты используют заглушки или demo и не делают платных вызовов AI.

Что проверяетсяГде находятся проверки
Формулы, задержки, синергии, бюджет, конфликты, границы и критический порогgame_api/test_engine.py
API, CSRF, сессии, изоляция игроков и сохранение результата при ошибкахgame_api/tests.py, интеграция Advisor
Загрузка .env и приоритет окруженияgame_api/test_environment.py
AI-контракты, неподтверждённые кандидаты и ошибочные ответыtests/test_agent.py
API-клиент, план и критические проблемы картыfrontend-tests

Контрольный план можно проверить прямо через движок, без браузера и внешнего AI:

python manage.py shell <<'PY'
from game_api.engine import simulate

plan = [
    {"measure_id": "M7", "district_id": "NURA"},
    {"measure_id": "M8", "district_id": "NURA"},
    {"measure_id": "M10", "district_id": "NURA"},
    {"measure_id": "M12", "district_id": None},
    {"measure_id": "M5", "district_id": "SARYARKA"},
]
result = simulate(decisions=plan)
assert abs(result["score"] - 56.5697) < 1e-9
assert result["budget_spent"] == 95
assert result["critical_count"] == 0
print("OK:", result["score"], result["budget_remaining"])
PY

Для проверки HTTP-маршрутов с CSRF и сессией без запуска внешнего сервера:

python manage.py test game_api.test_engine.ScoringAPIIntegrationTests

Дополнительно в браузере проверялись выбор районов, окна проблем, подбор мер, расчёт, изменение отметок на карте, повторные запросы и мобильная раскладка. Эти ручные/browser-проверки не входят в npm test; основной путь для их воспроизведения приведён выше.

Если запуск не удался

СимптомЧто проверить
Страница Django на 8000 возвращает 404Откройте интерфейс на адресе Vite, обычно http://127.0.0.1:5173
Каталог не загружается / «неожиданный ответ сервера»Откройте /api/catalog на порту Vite: ответ должен быть JSON. Убедитесь, что Django запущен; перезапустите Vite после переключения веток или изменения его конфигурации
npm: command not foundУстановите Node.js требуемой версии и перезапустите терминал
Ошибка таблицы сессийВыполните python manage.py migrate в нужном окружении
Порт занятИспользуйте уже запущенный процесс или остановите его. Адрес frontend смотрите в выводе Vite; для другого backend задайте DJANGO_API_TARGET в .env
Симуляция работает, но советник недоступенДля воспроизводимой демонстрации используйте demo; для реального AI проверьте ключ, модель и доступность сервиса, затем перезапустите Django. Таймаут внешнего запроса — 45 секунд
Изменения Python или .env не подхватилисьПерезапустите backend: объединённый launcher запускает его без autoreload и может переиспользовать уже работающий сервер

Структура репозитория

src/                  React-интерфейс, API-клиент и проверки плана
  components/         карта, иконки направлений, окно проблемы
game_api/             Django API, расчётный движок и интеграционные тесты
akim_ai/              Advisor, провайдеры модели, контракты и каталог
ThisIsTheAstana/       настройки и маршруты Django
frontend-tests/       тесты API-клиента, плана и проблем карты
tests/                тесты библиотеки Advisor
examples/             примеры запросов к CLI
docs/                 API, формулы, руководство Advisor и скриншоты
scripts/dev.sh        совместный запуск backend и frontend
.env.example          шаблон настроек без секретов

Границы текущей версии

  • Данные описывают учебную модель, а не текущее состояние города. Весь используемый каталог включён в репозиторий; живых городских потоков данных нет.
  • Карта иллюстративная, с условными границами. Текущие карта и AI-контракты рассчитаны на пять районов и идентификаторы включённого каталога.
  • Результаты детерминированы правилами модели, но не являются подтверждённым прогнозом реальных муниципальных эффектов. Полный поиск оптимального плана не выполняется.
  • Нет пользовательского входа в игровом интерфейсе, сохранённой библиотеки сценариев или экспорта. При перезагрузке страницы состояние интерфейса сбрасывается; серверная сессия может сохранять предыдущий расчёт и диалог, но их восстановление в UI ещё не реализовано.
  • AI может ошибаться или быть недоступен. Числовые результаты следует проверять по движку; demo демонстрирует только путь данных и заранее заданный ответ.
  • Конфигурация предназначена для локальной демонстрации. Для публикации потребуется настроить секреты Django, DEBUG, допустимые хосты, HTTPS и production-сервер. npm run build создаёт dist/; npm run preview проверяет сборку локально при работающем Django. В развёрнутом приложении frontend и /api должны быть доступны с одного origin.

Направления развития

Следующий шагПрактический результат
Подключить генерацию и проверку кандидатов к UIИгрок сравнивает несколько предложенных планов с результатами движка и сам выбирает вариант
Сохранение, сравнение и экспорт сценариевМожно вернуться к решениям и показать аргументы команде или преподавателю
Уточнить данные и откалибровать эффекты с экспертамиПоявится основание оценивать применимость модели вне учебной демонстрации
Добавить реальные геоданные и обобщить контракты каталогаПосле проверки модели можно адаптировать интерфейс к другим городам и наборам районов
Оценивать качество объяснений, добавить наблюдаемость и настройки развёртыванияПовысится надёжность работы с настоящим AI и готовность к пилотному использованию

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

Команда

УчастникЗона ответственности
ErasylРасчётный движок и Django API
TemirlanЛогика AI-советника
MirasДизайн и React-интерфейс
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
19
Авторы
6
Файлы
68
Ветки
4

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

era 7Coding-Lover-Git 7TeemFlash 2Temirlan 1Temirlan 1Erasyl 1

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

  • 2026-09-23 17:58Thank you for the opportunity!era
  • 2026-09-23 17:56Add standalone UI layout studio with diagnostic log exportCoding-Lover-Git
  • 2026-09-23 17:53that was a good event. Thank u <3era
  • 2026-09-23 17:28Restore interactive city map, icons, and problem dialogsera
  • 2026-09-23 17:11Merge design frontend and connect scoring engine and Advisorera
  • 2026-09-23 16:38Polish 2.5D city interface and validate decision flowCoding-Lover-Git
  • 2026-09-23 16:23Update designCoding-Lover-Git
  • 2026-09-23 16:23add uiCoding-Lover-Git
Все коммиты (19)
  • 2026-09-23 16:22Merge logic branch and connect Advisor to Django APIera
  • 2026-09-23 16:05Add complete advisor with chat memory, optimizations and CITemirlan
  • 2026-09-23 15:52added core API logicera
  • 2026-09-23 15:14intialize frontCoding-Lover-Git
  • 2026-09-23 14:59Merge remote-tracking branch 'origin/logic' into logicTeemFlash
  • 2026-09-23 14:59Add AKIM advisor projectTeemFlash
  • 2026-09-23 14:56testera
  • 2026-09-23 14:39Update README.mdCoding-Lover-Git
  • 2026-09-23 14:30Add Temirlan's role for AI logicTemirlan
  • 2026-09-23 14:29initErasyl
  • 2026-09-23 14:16the first model of ui designCoding-Lover-Git
Структура репозитория (68 файлов)
.env.example
.gitignore
.oxlintrc.json
ChatGPT Image 23 сент. 2026 г., 14_14_46.png
README.md
ThisIsTheAstana/__init__.py
ThisIsTheAstana/asgi.py
ThisIsTheAstana/settings.py
ThisIsTheAstana/urls.py
ThisIsTheAstana/wsgi.py
akim_ai/__init__.py
akim_ai/__main__.py
akim_ai/agent.py
akim_ai/catalog.json
akim_ai/contracts.py
akim_ai/prompts.py
akim_ai/providers.py
docs/advisor.md
docs/api.md
docs/engine.md
docs/images/overview.png
docs/images/problem.png
examples/plan.json
examples/request.json
frontend-tests/api.test.mjs
frontend-tests/city.test.mjs
frontend-tests/planning.test.mjs
game_api/__init__.py
game_api/engine.py
game_api/errors.py
game_api/integrations.py
game_api/services.py
game_api/test_engine.py
game_api/test_environment.py
game_api/test_logic_integration.py
game_api/tests.py
game_api/urls.py
game_api/validation.py
game_api/views.py
index.html
manage.py
package-lock.json
package.json
public/favicon.svg
public/icons.svg
requirements.txt
scripts/dev.sh
src/App.css
src/App.tsx
src/api.ts
src/assets/hero.png
src/assets/react.svg
src/assets/vite.svg
src/city.ts
src/components/CityMap.css
src/components/CityMap.tsx
src/components/DirectionIcon.tsx
src/components/ProblemDialog.css
src/components/ProblemDialog.tsx
src/index.css
src/main.tsx
src/planning.ts
tests/__init__.py
tests/test_agent.py
tsconfig.app.json
tsconfig.json
tsconfig.node.json
vite.config.ts
Ветки (4)

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

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

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