О проекте
Команда: Naiza-AI
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Веб-симулятор «Аким на 5 часов» на Next.js. Детерминированный движок Score, проигрывание 8 кварталов, жадный «Аким-автомат» для сравнения, совет из 4 LLM-агентов с секретарём и чат «Спросить город» на трёх языках.
Как устроено
Функции lib/engine validate(), simulate(), yearFrames(), recommend(), coach() и rivalPlan() считают Score по data/city.json (лаг (8−L)/8, синергии, клиппинг, штраф за значения ниже 40). Этот журнал — единственный источник чисел. Совет из четырёх агентов и секретаря (xAI grok-4.7 через пакет openai, ответы проверяются Zod) объясняет журнал, при недоступности модели доклад собирается по шаблону. Есть жадный рекомендатель следующего хода, «Тень другого решения» с пересчитанной дельтой, полка прогонов в data/runs.json и сравнение наборов. Карта на Leaflet/OSM.
Ключевые решения
- детерминированный simulate()
- жадный rival-план («Аким-автомат»)
- coach/рекомендация следующего хода
- мультиагентный совет + секретарь
- Zod-валидация структурированных ответов
- поквартальное проигрывание эффекта
- интерфейс RU/KK/EN
Особенности
Используется xAI Grok вместо OpenAI. Совет агентов может открыть карточку района, но числа берёт только из журнала. Интерфейс трилингвальный (рус/каз/англ), язык и тема переключаются фразами в чате. Есть портативный запуск через Akim.exe. В корне лежат посторонние файлы jev/laya_routing.py.
Стек
TypeScript · Next.js 15 · React 19 · Tailwind CSS 4 · Zod · Leaflet · OpenStreetMap · Vitest · C# (launcher Akim.exe)
Модели
grok-4.7 (xAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-e5c50c8d-naiza-ai.
README
README.mdАким на 5 часов
1. Название проекта
Аким на 5 часов
2. Краткое описание
Городскому управленцу, аналитику или команде на хакатоне нужно распределить один и тот же ограниченный бюджет между транспортом, экологией, соцсферой, безопасностью и городскими сервисами и понять, как это меняет качество среды.
Проект — веб-симулятор. Все начинают с бюджета 100 и одного синтетического набора: пять районов и десять показателей. Команда выбирает ровно пять мероприятий. Город отвечает баллом Score: 70% — средний уровень, 30% — самый слабый район, минус один балл за каждый показатель ниже 40. Рядом с числом есть объяснение компромиссов.
Районы и показатели условные. Это не официальная статистика, персональных данных в проекте нет.
3. Что реализовано
- Каталог из 14 мер и бюджет 100. Ровно пять мер, без повторов. Для районной меры обязателен район, для городской район не указывается.
- Проверка набора: превышение бюджета, больше двух мер одного направления, запрещённые пары (полосы и ЛРТ; парк и школа в одном районе; чистое топливо и модернизация сетей в одном районе). Недопустимый набор балл не получает, причина показывается в интерфейсе и возвращается сервером.
- Расчёт Score, среднего уровня, самого слабого района и числа показателей строго ниже 40. Остаток бюджета балл не повышает.
- Лаг на горизонте 8 кварталов: доля эффекта
(8 − L) / 8. Три синергии прибавляются целиком и лагом не режутся. - Живой экран набора: пять слотов, полоска бюджета, поиск по каталогу, фильтр мер для самого слабого района, список правил, показатели ниже 40 и статус синергий.
- Совет следующего хода: движок достраивает пятёрку и показывает три сильных первых шага. На карточке указан Score, если дальше тоже брать сильные ходы.
- Доклад: сильные стороны, риски, последствия на 8 кварталов, реплики вымышленных жителей, таблица районов и «Тень другого решения» с пересчитанной дельтой.
- Проигрывание восьми кварталов. Мера молчит свой лаг, затем каждый квартал добавляет одну восьмую эффекта. На 8-м квартале Score совпадает с итогом.
- Аким-автомат: жадный набор на том же каталоге. Его балл сравнивается с набором команды, набор можно открыть на экране решений.
- Карта OpenStreetMap с примерными точками пяти районов и локальными изображениями-образами районов.
- Полка прогонов на этой машине и сравнение двух последних наборов.
- Совет из четырёх агентов и секретаря, если задан ключ. Секретарь может открыть карточку района. Числа берутся из журнала. Если ключа нет, ответ не сошёлся или совет не успел, остаётся доклад по журналу.
- Кнопка «Спросить город»: диалог о текущем наборе. Фразы вроде «қазақша», «english» и «ночная тема» переключают язык и оформление. Языки интерфейса: русский, қазақша, English. Оформление: бумага, ночь, степь.
- Печать доклада из браузера и проверка
GET /api/health.
4. Как работает решение
- На старте команда видит бюджет 100, базовый Score 52,56 и карту пяти районов. Два показателя ниже 40 — школы и поликлиники Нуры.
- Команда набирает пять мер. Районная мера требует район, городская действует на всех. Интерфейс показывает остаток бюджета, правила и проекцию районов.
- «Открыть доклад» запускает расчёт. Движок применяет лаг и синергии, обрезает показатели в диапазон 0…100 и считает Score.
- На докладе видны сильные стороны, риски, последствия, карта и таблица «было / стало». Ползунок кварталов показывает, когда меры начинают работать.
- Если задан ключ, совет объясняет уже посчитанный журнал. Иначе текст собирается из этого журнала.
- Прогон можно положить на полку и сравнить с другим. Соседний набор из «Тени другого решения» можно подставить и пересчитать.
Контрольный пример методики: школа и поликлиника в Нуре, камеры в Нуре, городская платформа обращений, чистое топливо в Сарыарке. Стоимость 95, Score 56,54, провалов 0, синергия M10+M12.
5. Технологии
- TypeScript, React 19, Next.js 15 (App Router), Tailwind CSS 4
- Шрифты Fraunces и Source Sans 3 из пакетов
@fontsource - Vitest и tsx
- Zod для проверки структурированных ответов совета
- Leaflet и тайлы OpenStreetMap
- Пакет
openaiкак клиент к OpenAI-совместимому API - Модель по умолчанию
grok-4.7, адресhttps://api.x.ai/v1, ключXAI_API_KEY, имя модели можно задать переменнойXAI_MODEL
В репозитории нет вызовов api.openai.com и NVIDIA API.
6. Архитектура проекта
браузер
старт, набор, доклад, формула, полка, чат
│
▼
lib/engine
validate() simulate() yearFrames()
recommend() coach() rivalPlan()
│
▼
журнал: Score, средний, пол, провалы, синергии, вклады мер
│
├─ доклад по журналу, если модели нет
├─ POST /api/analyze совет и секретарь
├─ POST /api/chat ответ на вопрос по снимку набора
├─ POST /api/compare сравнение двух наборов
├─ GET, POST /api/runs полка в data/runs.json
└─ GET /api/health версия данных и базовый Score
Балл считает только simulate() в lib/engine. Клиент и сервер вызывают одну функцию. Модель объясняет готовый журнал и не является источником числа. Данные лежат в data/city.json, версия astana-rules-v2.
Экраны: /, /decide, /report, /method, /compare.
7. Установка и запуск
Нужен Node.js LTS. Команды из папки проекта в PowerShell:
npm install
copy .env.example .env
npm test
npm run demo
npm run dev
Открыть http://localhost:3000
Файл .env в git не попадает. Ключ можно оставить пустым. Для живого совета его записывают только локально и не публикуют в GitHub:
XAI_API_KEY=
XAI_MODEL=grok-4.7
На Windows файл start-local.cmd проверяет Node.js, при первом запуске выполняет npm install, создаёт .env из примера и открывает http://localhost:3000
Akim.exe в папке проекта — окно запуска. Рядом должны быть package.json, установленные node_modules и Node.js в PATH. Окно поднимает сервер на http://localhost:4173 и открывает браузер. Закрытие окна останавливает сервер.
После npm run build сервер запускается командой npm start.
Полная проверка типов, тестов и контрольных чисел:
npm run check
8. Как проверить решение
Без браузера:
npm test
npm run demo
npm run demo печатает три строки. На текущих данных это:
- база: Score 52.56, средний 56.86, пол 49.18, район
nura, критических провалов 2, резерв 100; - пример методики: Score 56.54, средний 58.08, пол 52.96, провалов 0, резерв 5, синергия
M10+M12; - дешёвый набор: Score 53.80, средний 58.10, пол 50.43, провалов 2, резерв 39, синергия
M10+M12.
Тесты дополнительно проверяют бюджет, число мер, повторы, лимит направления, конфликты, лаг, восьмой квартал и акима-автомата.
После запуска сервера:
curl http://localhost:3000/api/health
В ответе есть ok, версия данных и базовый Score.
В браузере:
- Открыть старт, ввести имя команды и нажать «Собрать набор».
- На экране набора нажать «Пример». Score около 56,54, остаток 5, провалов 0.
- Открыть доклад. Есть сильные стороны, риски, карта и таблица районов.
- Нажать «Смотреть два года» или сдвинуть ползунок кварталов. На 8-м квартале балл совпадает с итогом.
- Открыть «Тень другого решения» или «Открыть его набор» у акима-автомата. Набор и балл меняются.
- Положить прогон на полку, повторить с другим набором и нажать «Сравнить две последние».
- Нажать «Спросить город» и задать вопрос про текущий балл. В ответе не должно быть кода.
Набор дороже 100 через POST /api/analyze возвращает статус 400, модель при этом не вызывается.
9. Данные и интеграции
data/city.json: пять районов (Есиль, Алматы, Сарыарка, Байконур, Нура), доли населения, десять показателей от 0 до 100, 14 мер с ценой, лагом и эффектами, три синергии, три несовместимости, пять вымышленных жителей. Шкала направлена одинаково: 100 — лучше. Пробки и смог уже перевёрнуты.- Изображения районов лежат в
public/districts. Это образы для симулятора, не официальная фотофиксация. - Карта запрашивает тайлы
https://{s}.tile.openstreetmap.org. Точки районов примерные, это не официальные границы. Без интернета снимки остаются, подложка карты не загружается. - Живые ответы модели идут только с сервера на
https://api.x.ai/v1после расчёта или по снимку набора:POST /api/analyze,POST /api/chat,POST /api/compare. - Прогоны команд пишутся в
data/runs.jsonна машине, где запущен сервер. Файл указан в.gitignore. - Вызовов API OpenAI и NVIDIA в коде нет.
10. Ограничения
- Данные синтетические и не заменяют официальную статистику города.
- Нет учётных записей и нет общей полки между разными компьютерами.
- Без
XAI_API_KEYи сети живой совет, сравнение моделью и свободный ответ в чате недоступны. Score, журнал, кварталы, аким-автомат, тень решения, полка и доклад по журналу продолжают работать. - Названия мер в каталоге остаются на русском. Переводятся шапка, старт и подписи набора.
- Печать — страница браузера. Отдельный файл презентации проект не собирает.
Akim.exeне заменяет установку Node.js: это окно запуска для уже собранной папки проекта.- Публичной deployed-версии в репозитории нет.
11. Ссылка на deployed-версию
Развёрнутой публичной версии нет.
Локальные адреса после запуска:
npm run devилиstart-local.cmd: http://localhost:3000Akim.exe: http://localhost:4173
Авторы коммитов
История коммитов
- 2026-09-23 17:37Merge remote-tracking branch 'origin/main'Никита
- 2026-09-23 17:37Sync current project READMEНикита
- 2026-09-23 17:32Update README.mdKukumbus
- 2026-09-23 17:15Point README to cleaned portable packageНикита
- 2026-09-23 17:10Clarify local runtime and portable releaseНикита
- 2026-09-23 16:43Prepare HackAlem release with Akim.exe and READMEНикита
- 2026-09-23 16:21Add scenario comparison and district insightsНикита
- 2026-09-23 15:56Merge remote-tracking branch 'origin/main'Никита
Все коммиты (13)
- 2026-09-23 15:56Harden local app checks and runtime handlingНикита
- 2026-09-23 15:47Add files via uploadKukumbus
- 2026-09-23 15:18Add files via uploadnurba112
- 2026-09-23 14:49Add one-click local launcherНикита
- 2026-09-23 14:36Add Akim na 5 chasov applicationНикита
Структура репозитория (74 файлов)
.env.example .gitignore AGENTS.md Akim.exe CHANGELOG.md README.md app/api/analyze/route.ts app/api/chat/route.ts app/api/compare/route.ts app/api/health/route.ts app/api/runs/route.ts app/compare/page.tsx app/decide/page.tsx app/globals.css app/icon.svg app/layout.tsx app/method/page.tsx app/page.tsx app/report/page.tsx components/Assistant.tsx components/CityMap.tsx components/Frame.tsx components/RealMap.tsx components/ScorePlate.tsx components/score-color.ts data/city.json docs/PLAN.md docs/PROMPTS.md jev_adapter.py jev_routing.py launcher/Program.cs laya_adapter.py laya_routing.py lib/ai/briefing.ts lib/ai/compare.ts lib/ai/council.ts lib/ai/evidence.ts lib/ai/fallback.test.ts lib/ai/fallback.ts lib/ai/prompts.ts lib/ai/schemas.ts lib/assistant-commands.test.ts lib/assistant-commands.ts lib/draft.ts lib/engine/canon.ts lib/engine/city.ts lib/engine/coach.ts lib/engine/demo.ts lib/engine/format.ts lib/engine/insights.ts lib/engine/places.ts lib/engine/present.ts lib/engine/recommend.ts lib/engine/simulate.test.ts lib/engine/simulate.ts lib/engine/types.ts lib/plain-speech.test.ts lib/plain-speech.ts lib/prefs.tsx lib/store/runs.ts maker_backends.py next-env.d.ts next.config.ts package-lock.json package.json postcss.config.mjs public/districts/almaty.jpg public/districts/baikonur.jpg public/districts/esil.jpg public/districts/nura.jpg public/districts/saryarka.jpg start-local.cmd tsconfig.json vitest.config.ts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.