О проекте
Команда: 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.mdQalaBalance — Аким на 5 часов
Распределите бюджет города и узнайте, к чему приведут ваши решения.
QalaBalance — интерактивный симулятор управления Астаной с AI-помощником. Вы выбираете проекты, распределяете 100 бюджетных единиц между пятью сферами и сравниваете состояние города через один и три года.
Проект для HackAlem AI, кейс Astana Innovations «Аким на 5 часов».
Русский · Қазақша · English
Быстрый запуск · Настройка AI · Карта 2ГИС · Проверки · Документация

Все показатели, бюджеты, коэффициенты и результаты являются демонстрационными. Симулятор не представляет официальную оценку или прогноз развития Астаны.
Возможности
| Возможность | Что можно сделать |
|---|---|
| Городской бюджет | Выбрать по одному проекту в каждой из пяти сфер: транспорт, озеленение, социальная сфера, безопасность и городские сервисы |
| Каталог проектов | Сравнить 30 проектов по эффектам, стоимости, срокам, рискам и расходам на обслуживание |
| Результаты | Посмотреть индекс качества жизни AQLS, изменения пяти показателей, 10 возможных синергий и штрафы модели |
| AI-помощник | Задать свободный вопрос, продолжить разговор, обсудить решения или получить предложение по бюджету |
| Карта города | Изучить пять районов модели на карте 2ГИС или автономной SVG-схеме |
| Три языка | Переключить интерфейс, каталог, обучение, результаты и язык новых ответов AI между RU, KK и EN |
| Удобство | Пройти обучение из восьми шагов, выбрать тему оформления и продолжить работу с сохранённым в браузере черновиком |
Как проходит симуляция
- Ознакомьтесь с исходным состоянием города: стартовый AQLS — 58,3.
- Выберите пять проектов — по одному в каждой сфере.
- Распределите ровно 100 единиц, от 5 до 40 на сферу. Условный курс: 1 единица = 2 млрд ₸.
- Запустите расчёт и сравните горизонты 1 год / 3 года.
- Изучите эффекты, риски и объяснение результата, затем измените решения и сравните новую стратегию.
Результат рассчитывает детерминированный движок в браузере: одинаковый выбор и бюджет дают одинаковые показатели. 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-помощник
Помощник поддерживает свободный диалог: объяснения, математику, программирование, работу с текстом и вопросы о симуляторе. Он получает последние сообщения разговора, а для вопросов об игре — контекст проектов, бюджета и результатов. Доступны отмена запроса, повтор и начало нового диалога.
| Подключение | Настройка |
|---|---|
| Локально на Windows | Qwen3.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_AUTOSTART | 1 включает запуск установленной 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 для проверки данных |
| Backend | Python, FastAPI, Pydantic, Uvicorn |
| AI | OpenAI-совместимый клиент, 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 единиц, сравните оба горизонта и переключите язык. Выбор и бюджет должны сохраниться. При подключённой модели проверьте свободный вопрос и продолжение разговора.
Скриншоты
Сохранённые примеры интерфейса; внешний вид отдельных элементов может отличаться от текущей версии.
| Выбор проектов | Карта районов |
|---|---|
![]() | ![]() |
| Результат на английском | Тёмная тема на казахском |
![]() | ![]() |
Документация
- AI-помощник и подключение моделей
- Настройка карты 2ГИС
- Техническое задание
- Шаблон конфигурации backend
- Шаблон конфигурации карты
Контуры районов основаны на данных © участников OpenStreetMap, лицензия ODbL. Комплектная модель ISSAI Qwen3.5-9B-Kazakh распространяется по Apache 2.0, llama.cpp — по MIT; ссылки на источники приведены в инструкции AI. Каталог проектов и параметры симуляции подготовлены командой на основе ТЗ.
Авторы коммитов
История коммитов
- 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 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.



