AAYMA
RU
Войти

AQYL

Городской симулятор: 5 мер из 14 распределяются по районам в рамках бюджета 100, детерминированный движок считает Astana Quality of Life Score.

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

О проекте

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

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

Суть

Городской симулятор: 5 мер из 14 распределяются по районам в рамках бюджета 100, детерминированный движок считает Astana Quality of Life Score. Есть поиск одной замены, разложение Шепли и потоковый AI-совет экспертов.

Как устроено

FastAPI-движок (engine.py) загружает city.v2.json и считает лаги, охват, синергии и несовместимости, итог: Score = 0,7·среднее + 0,3·слабейший район − число критических показателей. Невалидный сценарий отклоняется до расчёта и до вызова AI. challenge.py ищет лучшую одиночную замену, shapley.py считает вклады мер. Совет (council) стримится в NDJSON: 6 запросов к OpenAI со structured output или демо-шаблоны. Frontend на Next.js проксирует API и показывает экраны Город → Решения → Результат с картой районов.

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

  • детерминированный scoring
  • значения Шепли
  • локальный поиск одной замены
  • NDJSON streaming
  • OpenAI structured output

Метрики

Контрольный расчёт: база 52,55768 → 56,54307 (расход 95); challenge 57,20556

Особенности

Score считает только движок, AI лишь объясняет. Python-зависимости закреплены SHA-256-хешами, в CI есть e2e на Playwright поверх Compose, Шепли-вклады мер показаны в UI.

Стек

Python 3.12 · FastAPI · Next.js · TypeScript · Docker Compose · Playwright · GitHub Actions · ruff · pytest

Модели

gpt-4o-mini


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

README

README.md

AQYL — «Аким на 5 часов»

Учебный AI-симулятор управления городом команды ILON. Пользователь распределяет общий бюджет 100 условных единиц, выбирает ровно пять инициатив и видит, как они меняют показатели пяти условных районов Астаны.

Для жюри (3–5 мин): docs/DEMO_SCRIPT.md — город → пример → Score → оспорить → слушать совет. Score считает движок; AI только объясняет.

Основной backend работает с синтетическим датасетом организаторов: 5 районов, 10 показателей, 14 мероприятий. Цена каждой меры фиксирована. Движок учитывает лаг, районный или городской охват, синергии и несовместимости. Сервер отклоняет превышение бюджета и другие недопустимые сценарии до расчёта и до вызова AI.

Astana Quality of Life Score вычисляет детерминированный движок:

Score = 0,7 × средняя оценка по населению + 0,3 × оценка слабейшего района − число показателей ниже 40

AI и демонстрационный совет получают готовый расчёт и объясняют компромиссы. Их текст не влияет на Score. Данные относятся к учебной модели и не являются прогнозом реальных городских последствий. В интерфейсе говорим о «состоянии модельного города» и «правилах синтетической модели».

Контрольный расчётБазаПример пяти решенийОдна замена (challenge)
Расходы095100
Средняя оценка по населению56,862458,0776—
Оценка слабейшего района49,1852,962554,9825
Критических показателей200
Score52,5576856,5430757,20556

Контрольный набор: M7/M8/M10 Нура, M12 город, M5 Сарыарка. Challenge находит замену M5 Сарыарка → M3 Нура (поиск ограничен одной заменой, не глобальный оптимум).

Что уже работает в интерфейсе

После запуска открывается игровой сценарий из трёх экранов:

  1. Город — базовый Score, критические пары, карта слева / выбранный район справа.
  2. Решения — компактные карточки мер (до 5 в ряд), выбор района, счётчик N/5, бюджет, preview.
  3. Результат — Score и KPI сразу на виду; карта и районы; объяснение; «Слушать совет»; вкладки challenge / Шепли / события / история.

Слот AI-совета (стрим council) на экране результата. Дополнительно: сравнение, Шепли, экспорт Markdown/PDF, учебные события и история — без изменения формулы Score.

Скрипт защиты: docs/DEMO_SCRIPT.md. Бонусы: docs/STAGE9_BONUS.md. UX: docs/UX_V2_NOTES.md. План: docs/ROADMAP.md.

Запуск приложения

Нужны Git и запущенный Docker с Compose v2. Из корня репозитория:

docker compose up --build

Для демонстрационного режима .env и API-ключ не нужны. После запуска:

На главной странице должны появиться статус подключения, режим AI, версия датасета, пять районов, четырнадцать мероприятий и экран «Город».

Фоновый запуск с ожиданием готовности:

docker compose up --build --detach --wait --wait-timeout 120
docker compose ps
docker compose down

Если порты заняты: WEB_PORT=3100 API_PORT=8100 docker compose up --build. Внутреннее соединение контейнеров остаётся на backend:8000.

Локальная разработка

Для backend нужен Python 3.12; для frontend — Node.js 24. Версии указаны в .python-version и .nvmrc. Backend, первый терминал:

cd backend
python3.12 -m venv .venv
.venv/bin/python -m pip install --require-hashes -r requirements-dev.txt
AI_PROVIDER=demo .venv/bin/python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

Frontend, второй терминал:

cd frontend
npm ci
npm run dev

Next.js по умолчанию обращается к http://127.0.0.1:8000. Если адрес backend другой, укажите API_INTERNAL_URL в окружении команды npm run dev или в frontend/.env.local. Корневой .env используется backend и Compose, но не загружается Next.js автоматически.

Реальный AI-совет (OpenAI / ключ Codex Platform)

Сейчас по умолчанию AI_PROVIDER=demo — программные шаблоны, не модель. Для живого совета:

  1. Скопируйте .env.example → .env в корне репозитория.
  2. Вставьте ключ с platform.openai.com/api-keys в OPENAI_API_KEY.
  3. Укажите AI_PROVIDER=openai и модель с structured output, например OPENAI_MODEL=gpt-4o-mini (coding-only Codex-модели для совета не рекомендуются).
  4. Перезапустите backend без префикса AI_PROVIDER=demo из backend/:
.venv/bin/python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
  1. В UI на результате: «Слушать совет» → режим должен стать «AI-модель OpenAI». Один полный совет = 6 запросов к модели. Ключ остаётся только на сервере.

API и прокси frontend

Backend (подробности в backend/README.md):

МетодПутьНазначение
GET/api/v1/catalogКаталог, baseline, default_scenario
POST/api/v1/preview0…5 решений, бюджет и ошибки
POST/api/v1/simulateРовно 5 допустимых → полный Score
POST/api/v1/challengeОдна лучшая допустимая замена
POST/api/v1/shapleyВклады пяти мер (Шепли)
POST/api/v1/council/streamNDJSON-совет экспертов

Frontend ходит на backend только через same-origin proxies: /api/health, /api/catalog, /api/preview, /api/simulate, /api/challenge, /api/shapley, /api/council/stream. Произвольный upstream URL не допускается. Если backend недоступен, страница показывает ошибку и кнопку повтора; Score не подменяется моками.

Пример контрольного расчёта:

curl -s -X POST http://127.0.0.1:8000/api/v1/simulate \
  -H 'Content-Type: application/json' \
  --data-binary @backend/examples/scenario.json

Проверки

Из backend/: .venv/bin/python -m pytest -q, .venv/bin/ruff check app tests, .venv/bin/ruff format --check app tests.

Из frontend/: npm run lint, npm run typecheck, npm run build, npm run test:e2e (нужен поднятый стек или CI).

GitHub Actions запускает backend, frontend и интеграционные проверки (Compose + Playwright) при push в main.

Зависимости Python закреплены с SHA-256 хешами в backend/requirements.txt и backend/requirements-dev.txt; frontend использует package-lock.json и npm ci. Исходные данные и формула: docs/DATASET_AND_RULES.md. Прежняя модель сохранена в docs/BACKEND_PROTOTYPE.md.

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

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

Yerbol Klimov 12Assima 5

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

  • 2026-09-23 17:51chore: drop phase/stage labels from UI copyYerbol Klimov
  • 2026-09-23 17:45feat: split decisions map layout and add bottom calculate CTAYerbol Klimov
  • 2026-09-23 17:37chore: harden defense demo path for jury reviewYerbol Klimov
  • 2026-09-23 17:09feat: add stage 9 bonuses and UX/UI V2 presentation layerYerbol Klimov
  • 2026-09-23 17:52docs: clarify UX screen navigation wordingAssima
  • 2026-09-23 16:47feat: add challenge, AI council UI, and defense docsYerbol Klimov
  • 2026-09-23 17:15docs: add stage nine bonus and UX V2 notesAssima
  • 2026-09-23 16:12feat: add Phase 4 simulator UI with district mapYerbol Klimov
Все коммиты (17)
  • 2026-09-23 16:10feat: add partial scenario preview APIYerbol Klimov
  • 2026-09-23 15:38chore: ignore local Playwright browser cache directoryYerbol Klimov
  • 2026-09-23 15:19feat: add phase 1 application infrastructureYerbol Klimov
  • 2026-09-23 15:58docs: add final developer handoff for AQYL demoAssima
  • 2026-09-23 15:30Implement official city dataset and scoring engineAssima
  • 2026-09-23 14:21docs: preserve supplied dataset rules and verified score examplesYerbol Klimov
  • 2026-09-23 14:08Merge simulator foundation into main and preserve team requirementsYerbol Klimov
  • 2026-09-23 14:00chore: checkpoint simulator backend and project documentationYerbol Klimov
  • 2026-09-23 13:57docs: describe AQYL city simulator concept and rulesAssima
Структура репозитория (102 файлов)
.dockerignore
.editorconfig
.env.example
.github/workflows/ci.yml
.gitignore
.nvmrc
.python-version
README.md
backend/Dockerfile
backend/README.md
backend/app/__init__.py
backend/app/challenge.py
backend/app/config.py
backend/app/council.py
backend/app/engine.py
backend/app/main.py
backend/app/preview.py
backend/app/schemas.py
backend/app/shapley.py
backend/app/validation.py
backend/data/city.v2.json
backend/examples/scenario.json
backend/pyproject.toml
backend/requirements-dev.in
backend/requirements-dev.txt
backend/requirements.in
backend/requirements.txt
backend/tests/conftest.py
backend/tests/test_api.py
backend/tests/test_challenge.py
backend/tests/test_council.py
backend/tests/test_dataset.py
backend/tests/test_preview.py
backend/tests/test_shapley.py
backend/tests/test_simulation.py
compose.yaml
docs/Akim_Project_Brief.docx
docs/Astana_Dataset_and_Rules.docx
docs/BACKEND_PROTOTYPE.md
docs/CODEX_STAGE6_HANDOFF.md
docs/DATASET_AND_RULES.md
docs/DEMO_SCRIPT.md
docs/DEVELOPER_HANDOFF.md
docs/PROJECT_BRIEF.md
docs/ROADMAP.md
docs/STAGE8_PART_B_CHECKLIST.md
docs/STAGE9_BONUS.md
docs/UX_V2_NOTES.md
frontend/.dockerignore
frontend/Dockerfile
frontend/e2e/challenge.spec.ts
frontend/e2e/connection.spec.ts
frontend/e2e/council.spec.ts
frontend/e2e/map.spec.ts
frontend/e2e/simulator.spec.ts
frontend/e2e/stage9.spec.ts
frontend/eslint.config.mjs
frontend/next-env.d.ts
frontend/next.config.ts
frontend/package-lock.json
frontend/package.json
frontend/playwright.config.ts
frontend/postcss.config.mjs
frontend/public/icon.svg
frontend/scripts/check-report.mts
frontend/src/app/api/catalog/route.ts
frontend/src/app/api/challenge/route.ts
frontend/src/app/api/council/stream/route.ts
frontend/src/app/api/health/route.ts
frontend/src/app/api/preview/route.ts
frontend/src/app/api/shapley/route.ts
frontend/src/app/api/simulate/route.ts
frontend/src/app/globals.css
frontend/src/app/health/route.ts
frontend/src/app/layout.tsx
frontend/src/app/page.tsx
frontend/src/components/AppChrome.tsx
frontend/src/components/ChallengePanel.tsx
frontend/src/components/CityScreen.tsx
frontend/src/components/ComparePanel.tsx
frontend/src/components/CouncilPanel.tsx
frontend/src/components/DecisionsScreen.tsx
frontend/src/components/DistrictMap.tsx
frontend/src/components/DistrictMapDynamic.tsx
frontend/src/components/EventsPanel.tsx
frontend/src/components/ExplainPanel.tsx
frontend/src/components/ExportBar.tsx
frontend/src/components/HistoryPanel.tsx
frontend/src/components/ResultScreen.tsx
frontend/src/components/ShapleyPanel.tsx
frontend/src/components/SimulatorProvider.tsx
frontend/src/data/astana-districts.json
frontend/src/data/district-profiles.json
frontend/src/data/events.json
frontend/src/lib/backend.ts
frontend/src/lib/contracts.ts
frontend/src/lib/history.ts
frontend/src/lib/labels.ts
frontend/src/lib/mapStyles.ts
frontend/src/lib/reportMarkdown.ts
frontend/src/lib/scenario.ts
frontend/tsconfig.json
Ветки (2)

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

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

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