AAYMA
RU
Войти

Сценарий Астаны

Streamlit-симулятор распределения бюджета (100 единиц на 5 мер из 14) по 5 районам и 5 направлениям с расчётом Astana Quality of Life Score…

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

О проекте

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

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

Суть

Streamlit-симулятор распределения бюджета (100 единиц на 5 мер из 14) по 5 районам и 5 направлениям с расчётом Astana Quality of Life Score, сравнением планов A/B в 3D-макете города и AI-объяснением.

Как устроено

Детерминированный движок citysim/engine.py применяет правила, лаги, эффекты и синергии мер к 10 показателям на горизонте 8 кварталов, считает Score и штраф Ncrit (пары ниже 40). Локальный ограниченный поиск или OpenAI предлагает альтернативу B, каждый кандидат проверяется ревизором через движок; LLM только объясняет готовый результат. Three.js-компонент визуализирует исходное состояние, A и B.

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

  • детерминированная симуляция с лагами и синергиями
  • bounded local search
  • проверка AI-кандидатов движком
  • OpenAI Responses API
  • Three.js 3D-визуализация

Метрики

Score 52.56→56.54 для плана A (Ncrit 2→0), лучший B 56.69 (стоимость 80)

Особенности

Воспроизводимый пример с точными ожидаемыми значениями Score; AI-предложения альтернатив проходят через ревизор-движок; run.py сам создаёт venv и запускает приложение, --check гоняет offline-тесты.

Стек

Python · Streamlit · Three.js · Vite · OpenAI SDK

Модели

gpt-6-luna (OpenAI Responses API)


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

README

README.md

Сценарий Астаны

Для кого и какую задачу решает

«Сценарий Астаны» — локальный симулятор для городского управленца, аналитика или команды, которая хочет сравнить варианты распределения бюджета. На пять выбранных мер дано 100 условных единиц. В городе пять условных районов, десять показателей по пяти направлениям и каталог из 14 мер. Пользователь сравнивает основной сохранённый план A с альтернативой B и видит, как решения меняют показатели и общий балл города (Astana Quality of Life Score): чем выше балл, тем лучше результат по формуле модели. Штраф Ncrit считает пары «район/показатель» со значением ниже 40.

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

Что можно сделать

  • Собрать план из пяти мер для районов или всего города, увидеть стоимость и остаток бюджета.
  • Проверить план по правилам и рассчитать изменения показателей, Score и числа критических пар.
  • Изучить таблицу результатов сценария: сравнить значения до и после, эффекты мер и выявленные риски.
  • Получить русское объяснение результата от ИИ и запросить вариант B через OpenAI API; при отсутствии ключа или сбое использовать локальный запасной режим.
  • Сохранить основной план A, создать альтернативу B вручную либо запустить ограниченный поиск замен для плана A.
  • Сравнить исходное состояние, A и B в интерактивном 3D-макете и таблице показателей. Можно выбрать район, направление и показатель, а для A/B подсветить различия.
  • Оставить план A или явно принять B как новый A.

Сценарий от входа до результата

Пользователь запускает приложение и открывает локальную страницу. Кнопка «Подставить пример из задания» загружает пять решений в черновик. После нажатия «Рассчитать и сохранить план A» движок проверяет правила и рассчитывает показатели и Score. Таблицы результатов показывают значения до и после, затраты и возможные ухудшения. Сохранённый результат отображается в разделе «Посмотрите на город»; изменения черновика не меняют его, пока пользователь не рассчитает новый план. Объяснение описывает готовый результат и не рассчитывает числа.

Для сравнения пользователь может нажать «Рассчитать текущий выбор как B» или «Подобрать вариант B для плана A». Модуль поиска и проверки рассматривает ограниченное число альтернатив и показывает лучшую из проверенных. B не заменяет A автоматически: для этого предусмотрено отдельное действие «Сделать B новым планом A». Подробная демонстрация с ожидаемыми значениями — в docs/DEMO.md.

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

Основной язык — Python 3.11 или новее. Интерфейс построен на Streamlit. Расчётная часть, модели данных и ревизор написаны на Python. 3D-компонент реализован на JavaScript с Three.js и собран локально с помощью Vite. Node.js нужен только для пересборки компонента после изменения его исходников; готовая сборка включена в репозиторий.

Прямые зависимости Python: streamlit==1.64.0, openai==3.19.0, python-dotenv==1.2.3. OpenAI SDK обращается к Responses API только в опциональном live-режиме. Зафиксированные прямые зависимости JavaScript: Three.js 0.186.0 и Vite 8.3.0. Полный перечень сторонних компонентов приведён в THIRD_PARTY.md, снимок разрешённых зависимостей — в docs/DEPENDENCIES.json.

app.py / ui/*                 интерфейс, черновик и сохранённые снимки A/B
       ↓
citysim/data.py               исходные данные районов, показателей и мер
citysim/engine.py             правила, лаги, эффекты, синергии, показатели и Score
       ↓ SimulationResult
citysim/ai.py                 объяснение результата (demo или OpenAI)
citysim/search.py             локальный поиск альтернатив
citysim/reviewer.py           проверка кандидатов движком
ui/scene.py                   подготовка данных для визуализации
       ↓ ScenePayload
components/city3d/            отображение исходного состояния, A и B в Three.js

citysim/engine.py рассчитывает все числовые результаты детерминированно и не обращается к сети или переменным окружения. AI объясняет расчёт; если live-режим предлагает альтернативы, каждое предложение всё равно проверяется движком. 3D-сцена показывает переданные ей результаты и сама не рассчитывает Score. Состояние планов хранится в сессии Streamlit; постоянной базы данных нет, поэтому перезагрузка страницы или сервера сбрасывает сессию.

Установка, API и запуск

Нужны Git, Python 3.11+ с pip и venv, а также интернет при первой установке зависимостей. Docker и Node.js для запуска приложения не нужны. Чтобы сразу пользоваться ИИ, подключите собственный ключ OpenAI локально: не отправляйте его в чат и не вставляйте в команду терминала.

git clone https://github.com/BAITC-Hacks/hack-a791087a-winx.git
cd hack-a791087a-winx

Создайте локальный .env из шаблона:

Windows PowerShell:

Copy-Item .env.example .env

macOS / Linux:

cp .env.example .env

Откройте .env в обычном текстовом редакторе (например, notepad .env в PowerShell, open -e .env в macOS или nano .env в Linux) и впишите свой ключ в OPENAI_API_KEY. Оставьте OPENAI_MODEL="gpt-6-luna", если эта модель доступна вашему API-проекту; иначе укажите идентификатор доступной модели. Оставьте DEMO_MODE=auto.

DEMO_MODE=auto
OPENAI_API_KEY=ваш_ключ_из_личного_API-проекта
OPENAI_MODEL=gpt-6-luna

Не вводите настоящий ключ в команды терминала и не отправляйте его в чат. Впишите его только в .env через текстовый редактор. Локальный .env исключён из Git.

Если личного API-доступа нет, пропустите создание .env и запустите приложение: режим auto использует локальное объяснение и поиск, когда ключ или модель не заданы. Интерфейс сообщит, что работает локально.

Запустите приложение:

python run.py

run.py сам создаст .venv, установит зависимости из requirements.txt и запустит Streamlit на http://127.0.0.1:8501. Если команда Python в системе называется python3, используйте python3 run.py. Остановка — Ctrl+C.

Для проверки без открытия браузера:

python run.py --headless

Для другого свободного порта:

python run.py --port 8502

Для установки зависимостей и запуска автоматических offline-проверок:

python run.py --check

Эта команда принудительно включает offline-режим и очищает ключ в дочернем процессе проверок. Она не выполняет платных запросов.

Воспроизводимый пример

После запуска выполните шаги в интерфейсе. Показатели и Score A детерминированы движком. В режиме auto объяснение и подбор B используют OpenAI API по нажатию соответствующих кнопок; если ключ или модель отсутствуют, интерфейс сообщает о локальном режиме, а при ошибке API показывает предупреждение и использует локальный результат. Перемещение по 3D-сцене API не вызывает.

  1. Исходный город показывает бюджет 100, базовый Score 52.5577 и Ncrit = 2.
  2. Нажмите «Подставить пример из задания». В черновике будут: M7 / Нура, M8 / Нура, M10 / Нура, M12 / город, M5 / Сарыарка.
  3. Нажмите «Рассчитать и сохранить план A». Ожидается стоимость 95, остаток 5, Score 56.5431 (точное значение модели: 56.54307) и Ncrit = 0.
  4. Нажмите «Показать объяснение результата», чтобы получить ответ OpenAI по сохранённому плану A. Если ключ или модель отсутствуют, интерфейс сообщит о локальном режиме; если API завершится ошибкой, приложение покажет предупреждение и локальный результат.
  5. Оставьте максимум замен равным 1, не закрепляйте решения и нажмите «Подобрать вариант B для плана A». OpenAI предложит альтернативу, а расчётный движок проверит её по правилам и рассчитает показатели. Состав live-варианта и его числа могут отличаться от воспроизводимого примера в docs/DEMO.md. Переключение районов, показателей и состояний в 3D не вызывает API. B не заменяет A без отдельного принятия.

Точный пример B без API

Чтобы проверить приведённые ниже эталонные числа, до запуска установите DEMO_MODE=1 в .env (или добавьте строку, если .env не создан) и перезапустите приложение. После нового расчёта A задайте одну замену без закреплённых решений и запустите подбор B. Локальный поиск проверит до 20 уникальных кандидатов за ревизию, включая отклонённые по правилам. Ожидаемый B стоит 80, имеет Score 56.6906 (56.69056) и Ncrit = 0: M5 / Сарыарка заменяется на M11 / Нура; прирост к A — около 0.14749. У него есть ухудшения отдельных показателей: Сарыарка E2 48.75 → 40 и C1 47.5 → 45; Нура T1 55 → 53.25. Это лучший из проверенных кандидатов, а не глобальный оптимум. Верните DEMO_MODE=auto и перезапустите приложение, чтобы включить API по конфигурации.

Для проверки бюджета измените в черновике M7 на M3: стоимость составит 101 (M3 стоит на 6 единиц дороже M7). Интерфейс сообщит о превышении бюджета, расчёт такого плана не выполняется. Подробный показ этого шага есть в docs/DEMO.md.

Данные и интеграции

В приложении локально зашиты синтетические данные организаторов: пять условных районов, доли населения, десять показателей по шкале 0–100, 14 мер с ценой, лагом и эффектами, бюджет 100 и горизонт восемь условных кварталов. Датасет и формулы приведены в docs/DATASET.md; обработка данных и проверка сценариев выполняются локально.

Приложение интегрируется с OpenAI Responses API для объяснения рассчитанного результата и подбора альтернативы B. В режиме auto эти обращения происходят по кнопкам «Показать объяснение результата» и «Подобрать вариант B для плана A» и могут тарифицироваться. Переключение районов, показателей и состояний в 3D API не вызывает. Настройка шаблона использует gpt-6-luna; доступность модели зависит от вашего проекта OpenAI. Если ключ или модель не заданы, интерфейс сообщает, что используется локальный режим. При ошибке API приложение показывает предупреждение и использует локальное объяснение или поиск. Полностью автономный запуск доступен с DEMO_MODE=1.

Переменные окружения и live-режим

Приложение читает .env из корня проекта, если он существует. Настройки процесса имеют приоритет над значениями в файле. Файл .env содержит личный API token и остаётся только локально; в Git сохраняется шаблон .env.example, но не ваш ключ.

ПеременнаяЗначение по умолчаниюНазначение
DEMO_MODEautoauto: использовать API при наличии ключа и модели, иначе локальный режим; 1: только локальный режим; 0: принудительно пробовать API, при отсутствии настроек или сбое показать предупреждение и использовать локальный результат.
OPENAI_API_KEYне заданВаш ключ OpenAI API; вводится только в локальный .env.
OPENAI_MODELgpt-6-luna в шаблонеМодель Responses API, доступная вашему проекту; при необходимости выберите другую.

Если не хотите сохранять ключ в .env, можно запустить отдельный live-launcher. Он запрашивает ключ скрытым вводом и не записывает его в файл:

python run.py --check
python scripts/start_live.py

При первом запуске live-launcher попросит идентификатор модели и ключ. Ключ передаётся только процессу приложения. API-вызов происходит после нажатия кнопки объяснения или подбора B. Использование API требует собственного доступа и может тарифицироваться.

Ограничения модели

  • Районы и показатели условные и синтетические. Макет 3D не является географической картой: расположение и здания условны, а высота столбцов отражает только выбранный показатель.
  • Score, эффекты и лаги следуют заданным формулам и параметрам набора. Они не предсказывают фактические результаты проектов или динамику реального города.
  • Нужно выбрать ровно пять разных мер, потратить не больше 100 единиц и взять не больше двух мер одного направления; покрывать все направления необязательно. Для набора, нарушившего правило, Score не рассчитывается.
  • Формула модели: Score = 0.7 × D_avg + 0.3 × min(D_d) − Ncrit, где D_avg — средневзвешенный по долям населения балл районов, min(D_d) — балл района с наименьшим результатом, Ncrit — число пар «район/показатель» со значением строго ниже 40. Промежуточные значения не округляются; показатели ограничиваются шкалой 0–100.
  • Пользовательский интерфейс позволяет задать 0 или 1 замену. За одну проверку альтернатив учитывается не более 20 уникальных кандидатов, включая отклонённые; поиск не охватывает все возможные сочетания и не доказывает глобальную оптимальность.
  • Планы и объяснения живут только в сессии приложения. После перезапуска или потери сессии их нужно создать заново.
  • События города и экспорт отчётов не реализованы. Для 3D требуется поддержка WebGL в браузере; при проблеме с рендерингом доступны таблицы показателей.
  • Live-режим зависит от доступности API, выбранной модели и пользовательского ключа; он не требуется для запуска, проверки или 3D.

Размещение

В репозитории не указана подтверждённая публичная ссылка на развёрнутую версию. Приложение запускается локально по адресу, приведённому выше.

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

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

Alikhan Chabarov 16AaaDddmyrza 12AaaDddmyrza 3

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

  • 2026-09-23 17:56new namingAlikhan Chabarov
  • 2026-09-23 17:48API: feat: clarify city scenarios and enable automatic OpenAI modeAlikhan Chabarov
  • 2026-09-23 17:24Merge pull request #4 from BAITC-Hacks/codex/review-ui-v2AaaDddmyrza
  • 2026-09-23 17:22merge: integrate current AI settings with A2 UI and V2AaaDddmyrza
  • 2026-09-23 17:20feat: integrate plan review and compare A/B in 3DAaaDddmyrza
  • 2026-09-23 17:11API: fix(ai): tune Luna reasoning and response budgetsAlikhan Chabarov
  • 2026-09-23 16:58API: docs: record live API diagnostics and current V1 statusAlikhan Chabarov
  • 2026-09-23 16:56Merge pull request #3 from BAITC-Hacks/codex/scene-v1AaaDddmyrza
Все коммиты (31)
  • 2026-09-23 16:51merge: sync completed A2 backend with the V1 sceneAaaDddmyrza
  • 2026-09-23 16:49feat: render saved plan A in the 3D city sceneAaaDddmyrza
  • 2026-09-23 16:44API: feat: implement bounded AI reviewer backendAlikhan Chabarov
  • 2026-09-23 16:27docs: restore overview ending periodAaaDddmyrza
  • 2026-09-23 16:27docs: remove overview ending periodAaaDddmyrza
  • 2026-09-23 16:24API: merge PR #2 scenario flow and assign parallel A2/V1 workAlikhan Chabarov
  • 2026-09-23 16:15docs: verify combined work and split reviewer and scene tasksAlikhan Chabarov
  • 2026-09-23 16:07API: feat: add bounded scenario reviewerAlikhan Chabarov
  • 2026-09-23 16:05chore: sync teammate audit and scenario handoffAaaDddmyrza
  • 2026-09-23 16:05feat: implement decision form saved plan and scenario explanationAaaDddmyrza
  • 2026-09-23 15:54API: docs: audit project after baseline 3D prototypeAlikhan Chabarov
  • 2026-09-23 15:46Merge pull request #1 from BAITC-Hacks/codex/3d-prototypeAaaDddmyrza
  • 2026-09-23 15:41feat: add interactive baseline 3D city prototypeAaaDddmyrza
  • 2026-09-23 15:24API: feat: define review and scene contractsAlikhan Chabarov
  • 2026-09-23 15:12test: cover scenario boundaries and effect tracesAlikhan Chabarov
  • 2026-09-23 15:09API: feat: implement scenario validation and simulationAlikhan Chabarov
  • 2026-09-23 15:06docs: checkpoint engine implementation startAlikhan Chabarov
  • 2026-09-23 14:59feat: prepare private OpenAI setup and require 3D deliveryAaaDddmyrza
  • 2026-09-23 14:33docs: split city simulator implementation between teammatesAaaDddmyrza
  • 2026-09-23 14:16docs: propose 3D city futures and AI reviewerAlikhan Chabarov
  • 2026-09-23 13:52docs: audit P0 and refine explainable scenario conceptAaaDddmyrza
  • 2026-09-23 13:34API: feat: scaffold simulator and define team contractAlikhan Chabarov
  • 2026-09-23 13:22chore: task, dataset and toolingAlikhan Chabarov
Структура репозитория (79 файлов)
.env.example
.gitignore
.streamlit/config.toml
AGENTS.md
README.md
THIRD_PARTY.md
app.py
citysim/__init__.py
citysim/ai.py
citysim/data.py
citysim/engine.py
citysim/labels.py
citysim/models.py
citysim/review_models.py
citysim/reviewer.py
citysim/search.py
components/__init__.py
components/city3d/.gitignore
components/city3d/README.md
components/city3d/__init__.py
components/city3d/frontend/package-lock.json
components/city3d/frontend/package.json
components/city3d/frontend/src/comparison.js
components/city3d/frontend/src/comparison.test.js
components/city3d/frontend/src/lifecycle.js
components/city3d/frontend/src/lifecycle.test.js
components/city3d/frontend/src/main.js
components/city3d/frontend/src/protocol.js
components/city3d/frontend/src/protocol.test.js
components/city3d/frontend/src/scene.js
components/city3d/frontend/src/style.css
components/city3d/frontend/src/tap.js
components/city3d/frontend/src/tap.test.js
components/city3d/frontend/src/view-state.js
components/city3d/frontend/src/view-state.test.js
components/city3d/frontend/vite.config.js
docs/API.md
docs/DATASET.md
docs/DEMO.md
docs/DEPENDENCIES.json
docs/ENGINE_REVIEW.md
docs/HANDOFF.md
docs/IDEA.md
docs/IMPLEMENTATION_PLAN.md
docs/NEXT_PARALLEL_STEPS.md
docs/PLAN.md
docs/PROJECT_REVIEW.md
docs/PROPOSAL.md
docs/REVIEW.md
docs/SECRETS.md
docs/TASK.md
docs/state/AaaDddmyrza.md
docs/state/alikhan.md
requirements.txt
run.py
scripts/dependency_report.py
scripts/start_live.py
tests/test_ai.py
tests/test_app.py
tests/test_app_review.py
tests/test_engine.py
tests/test_engine_boundaries.py
tests/test_live_launcher.py
tests/test_results.py
tests/test_review_contracts.py
tests/test_review_ui.py
tests/test_reviewer.py
tests/test_scene_component.py
tests/test_scene_payload.py
tests/test_search.py
tests/test_search_integrity.py
tests/test_state.py
ui/__init__.py
ui/forms.py
ui/labels.py
ui/results.py
ui/review.py
ui/scene.py
ui/state.py
Ветки (5)

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

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

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