AAYMA
RU
Войти

QalaBalance

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

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

О проекте

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

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

Суть

Интерактивный симулятор управления Астаной: игрок выбирает по одному проекту в 5 сферах, распределяет 100 бюджетных единиц и сравнивает индекс AQLS через 1 и 3 года; есть AI-помощник и карта районов 2ГИС.

Как устроено

Детерминированный движок в браузере (TypeScript) считает AQLS как взвешенную сумму 5 показателей минус штрафы, отдачу бюджета min(1.15, sqrt(бюджет/рекомендованный)), синергии, перекос финансирования и обслуживание. Каталог из 30 проектов и 10 синергий хранится в frontend/src/data. FastAPI-бэкенд проксирует диалог к OpenAI-совместимой LLM с контекстом проектов/бюджета/результатов; изменения от AI применяются только по кнопке, при недоступности модели показывается встроенное объяснение.

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

  • weighted AQLS index
  • diminishing returns sqrt
  • synergies and penalties
  • OpenAI-compatible client
  • llama.cpp local inference
  • 2GIS MapGL
  • Zod validation

Особенности

Локальный запуск казахоязычной Qwen3.5-9B-Kazakh (Q4_K_M, llama.cpp/Vulkan) с проверкой SHA-256 и резервом NVIDIA API. Три языка (RU/KK/EN), штрафы с отсылкой к КоАП РК, fallback на SVG-схему районов без ключа 2ГИС.

Стек

React 19 · TypeScript · Vite · Tailwind CSS · Recharts · Python · FastAPI · Pydantic · Docker Compose · nginx · Vitest · pytest

Модели

Qwen3.5-9B-Kazakh (ISSAI) · Ollama · NVIDIA API Catalog / NIM


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

README

README.md

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

Распределите бюджет города и узнайте, к чему приведут ваши решения.

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

Проект для HackAlem AI, кейс Astana Innovations «Аким на 5 часов».

Русский · Қазақша · English

Быстрый запуск · Настройка AI · Карта 2ГИС · Проверки · Документация

Экран результата симуляции

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

Возможности

ВозможностьЧто можно сделать
Городской бюджетВыбрать по одному проекту в каждой из пяти сфер: транспорт, озеленение, социальная сфера, безопасность и городские сервисы
Каталог проектовСравнить 30 проектов по эффектам, стоимости, срокам, рискам и расходам на обслуживание
РезультатыПосмотреть индекс качества жизни AQLS, изменения пяти показателей, 10 возможных синергий и штрафы модели
AI-помощникЗадать свободный вопрос, продолжить разговор, обсудить решения или получить предложение по бюджету
Карта городаИзучить пять районов модели на карте 2ГИС или автономной SVG-схеме
Три языкаПереключить интерфейс, каталог, обучение, результаты и язык новых ответов AI между RU, KK и EN
УдобствоПройти обучение из восьми шагов, выбрать тему оформления и продолжить работу с сохранённым в браузере черновиком

Как проходит симуляция

  1. Ознакомьтесь с исходным состоянием города: стартовый AQLS — 58,3.
  2. Выберите пять проектов — по одному в каждой сфере.
  3. Распределите ровно 100 единиц, от 5 до 40 на сферу. Условный курс: 1 единица = 2 млрд ₸.
  4. Запустите расчёт и сравните горизонты 1 год / 3 года.
  5. Изучите эффекты, риски и объяснение результата, затем измените решения и сравните новую стратегию.

Результат рассчитывает детерминированный движок в браузере: одинаковый выбор и бюджет дают одинаковые показатели. AI объясняет расчёт и помогает с решениями; предлагаемые изменения применяются только по кнопке пользователя.

Быстрый запуск

Понадобятся Git, Node.js 22.12+ и Python 3.12. Команды ниже предназначены для Windows PowerShell.

1. Получите проект

git clone https://github.com/BAITC-Hacks/hack-e9acc52d-bezdarez.git
cd hack-e9acc52d-bezdarez

2. Запустите backend

Выполните из корня проекта:

python -m venv backend/.venv
backend/.venv/Scripts/python.exe -m pip install -r backend/requirements-dev.txt
if (-not (Test-Path -LiteralPath .env)) { Copy-Item -LiteralPath .env.example -Destination .env }
backend/.venv/Scripts/python.exe -m uvicorn app.main:app --app-dir backend --host 127.0.0.1 --port 8000

3. Запустите frontend

Откройте второй терминал в корне проекта:

npm.cmd --prefix frontend ci
npm.cmd --prefix frontend run dev

Откройте localhost:5173. Если порт занят, используйте адрес, который напечатает Vite. Запросы /api автоматически направляются на backend по адресу http://127.0.0.1:8000.

Симулятор работает без ключей API. Для диалога подключите модель по инструкции ниже; без неё результаты сопровождаются встроенным объяснением. Для карты 2ГИС нужен отдельный браузерный ключ; без ключа доступна схема районов.

При следующих запусках достаточно команд uvicorn и npm.cmd --prefix frontend run dev — повторная установка зависимостей не требуется.

Запуск на Linux / macOS

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

python3 -m venv backend/.venv
backend/.venv/bin/python -m pip install -r backend/requirements-dev.txt
test -f .env || cp .env.example .env
backend/.venv/bin/python -m uvicorn app.main:app --app-dir backend --host 127.0.0.1 --port 8000

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

npm --prefix frontend ci
npm --prefix frontend run dev

Для AI используйте отдельно настроенный совместимый сервер или облачный API. Комплект локальной модели из scripts/setup_local_ai.py предназначен для Windows.

Запуск через Docker Compose

Из корня проекта с подготовленным .env:

docker compose up --build

Приложение: localhost:8080. API: localhost:8000/api/health.

Compose запускает frontend и backend. Для AI требуется отдельно доступный сервер: адрес 127.0.0.1 внутри контейнера относится к самому контейнеру. Переносимая Windows-модель в контейнере автоматически не запускается. Текущая Docker-сборка не передаёт ключ 2ГИС и использует SVG-схему.

AI-помощник

Помощник поддерживает свободный диалог: объяснения, математику, программирование, работу с текстом и вопросы о симуляторе. Он получает последние сообщения разговора, а для вопросов об игре — контекст проектов, бюджета и результатов. Доступны отмена запроса, повтор и начало нового диалога.

ПодключениеНастройка
Локально на WindowsQwen3.5-9B-Kazakh от ISSAI, квантование Q4_K_M, llama.cpp / Vulkan. Установщик загружает около 5,7 ГБ и проверяет SHA-256
Собственный серверOpenAI-совместимый API, например уже настроенная Ollama или vLLM
Облачный провайдерСовместимый API; в .env.example приведён пример NVIDIA API Catalog

Полная инструкция подключения AI →

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

Если модель недоступна, чат показывает сообщение об ошибке и кнопку повтора. Экран результата при этом продолжает работать со встроенным объяснением, а подсказки по решениям доступны без AI.

Карта 2ГИС

Скопируйте шаблон из корня проекта:

if (-not (Test-Path -LiteralPath frontend/.env.local)) { Copy-Item -LiteralPath frontend/.env.example -Destination frontend/.env.local }

В frontend/.env.local укажите свой ключ с доступом к Map Tiles / MapGL JS API:

VITE_DGIS_API_KEY=ваш_браузерный_ключ

Перезапустите Vite. Для production ключ задаётся перед сборкой frontend. Это браузерный ключ: ограничения доменов и квоты настраиваются в кабинете 2ГИС.

Без ключа или при ошибке загрузки приложение использует SVG-схему. Контуры пяти районов модели приблизительные и не являются актуальными официальными административными границами.

Подключение и поведение карты →

Конфигурация

Корневой .env читает backend. Файл frontend/.env.local содержит настройки сборки frontend. Оба файла исключены из Git; примеры доступны в .env.example и frontend/.env.example.

ПеременнаяНазначение
LLM_API_URLАдрес совместимого API, включая /v1
LLM_MODELТочное имя модели на выбранном сервере
LLM_API_KEYКлюч AI-провайдера; остаётся на backend
LLM_TIMEOUT_SECONDSТаймаут запроса: в шаблоне 25 секунд, для комплектной локальной модели — 90
LOCAL_AI_AUTOSTART1 включает запуск установленной Windows-модели вместе с backend
NVIDIA_API_KEY, NVIDIA_MODELНеобязательный резервный AI-провайдер
CORS_ORIGINSРазрешённые адреса frontend для прямых запросов к API
VITE_DGIS_API_KEYБраузерный ключ карты в frontend/.env.local

Если backend работает на другом порту, задайте адрес перед запуском frontend, например:

$env:VITE_PROXY_TARGET = 'http://127.0.0.1:8011'
npm.cmd --prefix frontend run dev

Расчёт и архитектура

Индекс Astana Quality of Life Score (AQLS) объединяет пять показателей:

AQLS = Мобильность × 0,25 + Экология × 0,20
     + Социальный комфорт × 0,20 + Безопасность × 0,20
     + Городские сервисы × 0,15 − штрафы

Отдача от бюджета растёт по формуле min(1.15, sqrt(бюджет / рекомендованный бюджет)). Движок учитывает эффекты проектов, синергии, перекос финансирования, долгосрочные множители и обслуживание. Коэффициенты и исходные данные находятся в frontend/src/data, расчёт — в calculateSimulation.ts.

flowchart LR
    UI[Интерфейс и решения] --> Engine[Движок симуляции]
    Data[Каталог и коэффициенты] --> Engine
    Engine --> Result[Показатели и результат]
    Result --> Fallback[Встроенное объяснение]
    Result --> API[FastAPI]
    UI -->|Диалог| API
    API <--> LLM[Локальная модель или облачный API]
    API --> Reply[Ответ и предложения]
    Reply --> UI
СлойТехнологии
ИнтерфейсReact 19, TypeScript, Vite 8, Tailwind CSS 4, Recharts, Lucide
ДвижокЧистые TypeScript-функции, Zod для проверки данных
BackendPython, FastAPI, Pydantic, Uvicorn
AIOpenAI-совместимый клиент, llama.cpp для комплектной локальной модели
ПроверкиVitest, pytest, TypeScript, Oxlint
КонтейнерыDocker Compose, nginx

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

frontend/src/
  pages/                   Старт, выбор проектов, результаты
  components/              Карта, помощник, обучение, графики и настройки
  data/                    Проекты, районы, коэффициенты и переводы
  lib/                     Расчёт, локализация, хранение и API-клиенты
  types/                   Типы данных
backend/app/
  main.py                  Приложение FastAPI
  explain.py               API объяснений и помощника
  assistant.py             История, контекст и проверка действий
  llm.py                   Клиент языковых моделей
  local_ai.py              Запуск локальной модели
backend/tests_explain/     Тесты API
scripts/setup_local_ai.py  Установка локальной модели для Windows
docs/                     Инструкции, ТЗ и скриншоты

API

МетодПутьНазначение
GET/api/healthСостояние backend, настройка AI и готовность локальной модели
POST/api/assistВопрос, история разговора, язык ru / kk / en и контекст решений
POST/api/explainОбъяснение уже рассчитанного результата на выбранном языке

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

Проверки

Из корня проекта после установки зависимостей:

npm.cmd --prefix frontend test
npm.cmd --prefix frontend run build
npm.cmd --prefix frontend run lint -- src
backend/.venv/Scripts/python.exe -m pytest -c backend/pytest.ini backend/tests_explain -q

На Linux/macOS используйте npm и backend/.venv/bin/python. Автотесты API используют подставные ответы провайдера; действующий ключ и запущенная модель для них не требуются.

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

Скриншоты

Сохранённые примеры интерфейса; внешний вид отдельных элементов может отличаться от текущей версии.

Выбор проектовКарта районов
Выбор проектовКарта районов
Результат на английскомТёмная тема на казахском
Результат на английскомТёмная тема на казахском

Документация

Контуры районов основаны на данных © участников OpenStreetMap, лицензия ODbL. Комплектная модель ISSAI Qwen3.5-9B-Kazakh распространяется по Apache 2.0, llama.cpp — по MIT; ссылки на источники приведены в инструкции AI. Каталог проектов и параметры симуляции подготовлены командой на основе ТЗ.

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

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

Dras2e 20Abylayts 4tutto-passa6767 3tutto-passa6767 2Dras2e 2

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

  • 2026-09-23 17:47docs: rewrite project README and setup guidetutto-passa6767
  • 2026-09-23 17:39feat: improve AI assistant, 2GIS maps and Kazakh/English supporttutto-passa6767
  • 2026-09-23 17:29fix: английские подписи таблицы «до и после», радара и сумм в тенгеDras2e
  • 2026-09-23 17:28fix: инструкция о языке ответа дублируется в сообщении пользователя для локальной моделиDras2e
  • 2026-09-23 17:24docs: запуск локальной LLM (Ollama) и резерва NVIDIA в README и .env.exampleDras2e
  • 2026-09-23 17:24feat: системная аналитика, обучение и реакции жителей на kk/enDras2e
  • 2026-09-23 17:22feat: английский язык и перевод данных каталога на kk/enDras2e
  • 2026-09-23 17:12Update tz.txtAbylayts
Все коммиты (31)
  • 2026-09-23 16:51Update test_ai_analysis.pyDras2e
  • 2026-09-23 16:23Update testtesttutto-passa6767
  • 2026-09-23 16:00Update tz.txtAbylayts
  • 2026-09-23 15:49feat: локальная LLM на GPU ноутбука (Ollama) с резервом NVIDIA APIDras2e
  • 2026-09-23 15:44fix: пробел между районом Алматы и рекой Есиль на картеDras2e
  • 2026-09-23 15:34docs: README и скриншоты — помощник, обучение, штрафы, тёмная темаDras2e
  • 2026-09-23 15:33fix: падение приложения при вопросе помощнику и отображение коэффициентов штрафовDras2e
  • 2026-09-23 15:25feat: AI-помощник, обучение, настройки (тёмная тема, қазақша), окно штрафов с КоАП РКDras2e
  • 2026-09-23 15:19proverkatutto-passa6767
  • 2026-09-23 15:16feat: каталог расширен до 30 проектов и 10 синергийDras2e
  • 2026-09-23 15:15fix: Есиль перекрывал Нуру при наведении на картеDras2e
  • 2026-09-23 15:05feat: интерактивная карта районов Астаны и бюджет в тенгеDras2e
  • 2026-09-23 15:00Add comprehensive tests for HTTP API endpointsAbylayts
  • 2026-09-23 14:59пример_api.pyDras2e
  • 2026-09-23 14:55feat: дизайн в стиле городских сервисов Астаны и сильнее блок объясненияDras2e
  • 2026-09-23 14:39docs: README по положению и ТЗ; fix: падение экрана решений и рекомендацииDras2e
  • 2026-09-23 14:33feat: /api/explain на NVIDIA-совместимом LLM с проверкой ответаDras2e
  • 2026-09-23 14:30feat: UI по ТЗ — старт, распределение бюджета, результатDras2e
  • 2026-09-23 14:25feat: детерминированный Simulation Engine по ТЗ (AQLS, 1/3 года, синергии, штрафы)Dras2e
  • 2026-09-23 14:20feat: клиент NVIDIA NIM/OpenAI-совместимого APIDras2e
  • 2026-09-23 14:19Add "Аким на 5 часов" city simulator MVPtutto-passa6767
  • 2026-09-23 14:04Update test dras1eAbylayts
  • 2026-09-23 14:03Create test dras1eDras2e
Структура репозитория (152 файлов)
.dockerignore
.env.example
.gitignore
README.md
backend/.dockerignore
backend/Dockerfile
backend/app/__init__.py
backend/app/assistant.py
backend/app/data/districts.json
backend/app/data/initiatives.json
backend/app/data/rules.json
backend/app/engine/__init__.py
backend/app/engine/data.py
backend/app/engine/simulation.py
backend/app/engine/validator.py
backend/app/explain.py
backend/app/llm.py
backend/app/local_ai.py
backend/app/main.py
backend/app/models/__init__.py
backend/app/models/schemas.py
backend/app/routers/__init__.py
backend/app/routers/api.py
backend/app/services/__init__.py
backend/app/services/ai_analysis.py
backend/app/services/catalog.py
backend/app/services/scoring.py
backend/app/services/simulation.py
backend/app/services/validation.py
backend/pytest.ini
backend/requirements-dev.txt
backend/requirements.txt
backend/tests/__init__.py
backend/tests/test_ai_analysis.py
backend/tests/test_api.py
backend/tests/test_api_edges.py
backend/tests/test_engine.py
backend/tests/test_engine_invariants.py
backend/tests_explain/test_assistant.py
backend/tests_explain/test_explain.py
backend/tests_explain/test_llm_schema.py
backend/tests_explain/test_local_ai.py
backend/tests_explain/test_locales.py
docker-compose.yml
docs/2gis.md
docs/assistant.md
docs/screenshots/assistant.png
docs/screenshots/dark-kk.png
docs/screenshots/decisions.png
docs/screenshots/map.png
docs/screenshots/mobile-result.png
docs/screenshots/mobile.png
docs/screenshots/overview.png
docs/screenshots/penalties.png
docs/screenshots/result-1y.png
docs/screenshots/result-3y.png
docs/screenshots/result-en.png
docs/screenshots/results.png
docs/screenshots/simulator.png
docs/screenshots/start.png
docs/screenshots/tour.png
docs/tz.txt
frontend/.dockerignore
frontend/.env.example
frontend/.gitignore
frontend/.oxlintrc.json
frontend/Dockerfile
frontend/README.md
frontend/index.html
frontend/nginx.conf
frontend/package-lock.json
frontend/package.json
frontend/public/favicon.svg
frontend/src/App.tsx
frontend/src/components/AiExplanation.tsx
frontend/src/components/Assistant.tsx
frontend/src/components/AssistantMessage.test.tsx
frontend/src/components/AssistantMessage.tsx
frontend/src/components/BudgetChart.tsx
frontend/src/components/BudgetHeader.tsx
frontend/src/components/BudgetSlider.tsx
frontend/src/components/CategoryNavigation.tsx
frontend/src/components/CitizenReactionCard.tsx
frontend/src/components/CityMap.tsx
frontend/src/components/DGisMap.tsx
frontend/src/components/Modal.tsx
frontend/src/components/Ornament.tsx
frontend/src/components/PenaltiesModal.tsx
frontend/src/components/ProjectCard.tsx
frontend/src/components/ResultComparison.tsx
frontend/src/components/ScoreGauge.tsx
frontend/src/components/ScoreRadarChart.tsx
frontend/src/components/SettingsModal.tsx
frontend/src/components/StrategyProfile.tsx
frontend/src/components/TopBar.tsx
frontend/src/components/Tour.tsx
frontend/src/components/ui.tsx
frontend/src/data/astanaMap.ts
frontend/src/data/baseline.ts
frontend/src/data/categoryVisuals.ts
frontend/src/data/districtGeography.ts
frontend/src/data/districts.ts
frontend/src/data/fallbackTexts.ts
frontend/src/data/locales/map.ts
frontend/src/data/locales/penalties.ts
frontend/src/data/locales/projects.ts
frontend/src/data/locales/tour.ts
frontend/src/data/projects.ts
frontend/src/data/realFines.ts
frontend/src/data/synergies.ts
frontend/src/index.css
frontend/src/lib/advisor.ts
frontend/src/lib/assistant.test.ts
frontend/src/lib/assistant.ts
frontend/src/lib/assistantChat.test.ts
frontend/src/lib/assistantChat.ts
frontend/src/lib/assistantLocale.test.ts
frontend/src/lib/buildAiPayload.ts
frontend/src/lib/calculatePenalties.ts
frontend/src/lib/calculateProjectEffect.ts
frontend/src/lib/calculateSimulation.ts
frontend/src/lib/calculateSynergies.ts
frontend/src/lib/determineProfile.ts
frontend/src/lib/dgis.test.ts
frontend/src/lib/dgis.ts
frontend/src/lib/districtProjection.ts
frontend/src/lib/districts.test.ts
frontend/src/lib/effects.test.ts
frontend/src/lib/explainApi.ts
frontend/src/lib/format.test.ts
frontend/src/lib/format.ts
frontend/src/lib/generateFallbackExplanation.ts
frontend/src/lib/i18n.test.tsx
frontend/src/lib/i18n.tsx
frontend/src/lib/localizedContent.test.ts
frontend/src/lib/localizedContent.ts
frontend/src/lib/simulation.test.ts
frontend/src/lib/storage.ts
frontend/src/main.tsx
frontend/src/pages/ResultPage.tsx
frontend/src/pages/SimulatorPage.tsx
frontend/src/pages/StartPage.tsx
frontend/src/types/ai.ts
frontend/src/types/project.ts
frontend/src/types/simulation.ts
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
scripts/setup_local_ai.py
test dras1e
testtest

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

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

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