О проекте
Команда: 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 не вызывает.
- Исходный город показывает бюджет 100, базовый Score 52.5577 и Ncrit = 2.
- Нажмите «Подставить пример из задания». В черновике будут: M7 / Нура, M8 / Нура, M10 / Нура, M12 / город, M5 / Сарыарка.
- Нажмите «Рассчитать и сохранить план A». Ожидается стоимость 95, остаток 5, Score 56.5431 (точное значение модели: 56.54307) и Ncrit = 0.
- Нажмите «Показать объяснение результата», чтобы получить ответ OpenAI по сохранённому плану A. Если ключ или модель отсутствуют, интерфейс сообщит о локальном режиме; если API завершится ошибкой, приложение покажет предупреждение и локальный результат.
- Оставьте максимум замен равным 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_MODE | auto | auto: использовать API при наличии ключа и модели, иначе локальный режим; 1: только локальный режим; 0: принудительно пробовать API, при отсутствии настроек или сбое показать предупреждение и использовать локальный результат. |
OPENAI_API_KEY | не задан | Ваш ключ OpenAI API; вводится только в локальный .env. |
OPENAI_MODEL | gpt-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.
Размещение
В репозитории не указана подтверждённая публичная ссылка на развёрнутую версию. Приложение запускается локально по адресу, приведённому выше.
Авторы коммитов
История коммитов
- 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
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.