О проекте
Команда: AI-Rehub
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Симулятор городского бюджета: пользователь выбирает 5 мер на 100 единиц бюджета, движок считает итоговый Quality of Life Score по пяти районам Астаны, а советник ищет лучшую замену одной меры.
Как устроено
Детерминированный TypeScript-движок (src/domain) проверяет план: бюджет, уникальность мер, лимиты по направлениям, несовместимости. Затем он применяет эффекты с лагами, синергиями и границами и считает Score как взвешенную по населению среднюю, оценку худшего района и штраф за показатели ниже 40. Советник перебирает все допустимые планы с заменой одной меры. Серверный POST /api/analyze заново пересчитывает сценарий. OpenAI (Responses API, Structured Outputs) только ранжирует уже проверенные карточки выводов; без ключа работает локальный анализ.
Ключевые решения
- детерминированный движок сценариев
- полный перебор замен одной меры (контрфактический советник)
- OpenAI Structured Outputs
- Zod-валидация
- детерминированный fallback
Особенности
LLM не считает числа: она лишь возвращает порядок ID проверенных карточек, а неизвестные ID отбрасываются. Сделан аудит с независимым пересчётом 10 010 планов и сверкой с PDF-оракулом. Интерфейс на трёх языках (ru/kk/en), есть публичное демо.
Стек
TypeScript · Next.js 16 · React 19 · Tailwind CSS 4 · Zod · Vitest · Playwright · GitHub Actions
Модели
OpenAI gpt-6-sol
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-7f85cb98-ai-rehub.
README
README.mdАким на 5 часов
Интерактивный симулятор городских решений для HackAlem AI. Он помогает сравнить, как пять мер при ограниченном бюджете меняют показатели пяти районов Астаны. Проект рассчитан на участников хакатона, жюри и всех, кому нужно быстро увидеть последствия выбранного плана в рамках учебной модели.
Главная идея: расчётный движок проверяет решения и считает результат, советник перебирает допустимые замены одной меры, а AI расставляет по важности уже проверенные выводы. Числа и эффекты не рассчитываются языковой моделью.
Что реализовано
- Выбор пяти разных городских и районных мер из каталога с бюджетом 100 единиц, проверкой ограничений и пояснением ошибок.
- Расчёт исходного и итогового Astana Quality of Life Score, показателей районов, критических значений и влияния выбранных мер.
- Контрфактический советник: перебор допустимых замен одной меры, сравнение планов и применение найденной замены.
- Объяснение результата по сильным сторонам, рискам, компромиссам и рекомендациям. При наличии API-ключа OpenAI выбирает приоритет проверенных фактов; без ключа доступен локальный детерминированный анализ.
- Интерфейс на русском, казахском и английском языках, светлая и тёмная темы, сохранение плана и настроек в
localStorageбраузера. - Серверный
POST /api/analyze, который самостоятельно пересчитывает переданные решения и не принимает клиентские Score или бюджет как достоверные данные.
Как работает решение
- Пользователь выбирает ровно пять мер. Для районной меры указывает район; городская применяется ко всем пяти районам.
- Валидатор проверяет бюджет, уникальность мер, лимит по направлениям и несовместимости. При ошибке расчёт не запускается.
- Движок применяет эффекты мер с учётом задержки, синергий и границ показателей. Затем считает оценку каждого района и общий Score.
- Советник перебирает допустимые планы, отличающиеся заменой одной меры, и показывает лучший по Score вариант вместе с изменением бюджета и районов.
- Клиент отправляет идентификаторы решений в
/api/analyze. Сервер повторно рассчитывает сценарий и формирует проверенные выводы. OpenAI может определить порядок их показа; при отсутствии ключа или сбое показывается локальный анализ.
Формула и полный контракт расчёта описаны в документации движка. Итог учитывает среднюю оценку с весами по населению, оценку самого слабого района и штраф за показатели ниже 40.
Технологии
| Область | Используется |
|---|---|
| Приложение | TypeScript, React 19, Next.js 16 (App Router), CSS и Tailwind CSS 4 |
| Расчёт | Локальный TypeScript-модуль src/domain/ и данные src/data/ |
| AI | Официальный OpenAI SDK, Responses API и Structured Outputs; модель из OPENAI_MODEL, по умолчанию gpt-6-sol |
| Проверка данных | Zod на границе AI API |
| Тестирование | Vitest, Node.js test runner и Playwright |
| Хранение настроек | localStorage браузера |
OpenAI API — единственный внешний сервис, используемый приложением, и он необязателен для запуска. База данных в репозитории не настроена.
Архитектура проекта
src/data/ Районы, показатели, меры и правила учебной модели
↓
src/domain/ Валидация → расчёт сценария → поиск замены
↓ ↓
src/app/page.tsx Интерфейс POST /api/analyze
src/components/ ↓
Серверный пересчёт → проверенные факты
↓
OpenAI или локальный анализ
src/lib/ai/ содержит адаптер результатов движка, локальный анализ, вызов OpenAI и клиентский хук. Серверный маршрут расположен в src/app/api/analyze/route.ts. Числа в интерфейсе берутся из движка. Модель получает проверенные карточки, стоимость и лаги выбранных мер, реализованные эффекты, изменения районов и сравнение с заменой. Она возвращает только идентификаторы карточек в порядке важности; неизвестные идентификаторы и ошибки API приводят к локальному анализу.
Установка и запуск
Требуются Node.js 22.18 или новее и npm (версия Node указана в package.json). Выполняйте команды из корня репозитория:
npm ci
npm run dev
Откройте http://localhost:3000. Без дополнительной настройки доступны симуляция, советник и локальное объяснение.
Для необязательного OpenAI-анализа скопируйте .env.example в .env.local и добавьте действующий ключ OpenAI API:
cp .env.example .env.local
В PowerShell: Copy-Item .env.example .env.local. Содержимое файла:
OPENAI_API_KEY=ваш_ключ_OpenAI_API
OPENAI_MODEL=gpt-6-sol
Выберите в OPENAI_MODEL модель, доступную вашему API-аккаунту и поддерживающую нужный формат ответа. После изменения .env.local перезапустите сервер. Ключ используется только на сервере.
Для локального production-запуска:
npm run build
npm run start
Как проверить решение
Сценарий для жюри
- Откройте главную страницу и нажмите «Загрузить пример». План содержит M7/Нура, M8/Нура, M10/Нура, M12/весь город и M5/Сарыарка.
- Проверьте бюджет 95 из 100 и изменение Score 52,56 → 56,54. Значения до округления:
52.55768 → 56.54307. - Нажмите «Найти лучшую замену». Советник показывает замену M5/Сарыарка → M3/Нура: бюджет 100, новый Score
57.20556(на экране57,21). - Нажмите «Применить замену», затем «Рассчитать сценарий». Изменение плана вызывает новый расчёт; прежний результат не остаётся результатом нового плана.
- Нажмите «Сбросить» и выберите меньше пяти мер. Интерфейс показывает ошибку выбора и блокирует расчёт.
На русском языке при настроенном ключе может появиться анализ с меткой OpenAI. Без ключа тот же сценарий сопровождается локальным анализом. Казахская и английская версии используют локализованный локальный анализ.
Автоматические проверки
npm run check
npx playwright install chromium
npm run test:e2e
npm run check последовательно выполняет проверку типов, линтер, тесты приложения и движка, production-сборку и smoke-проверку собранного движка. Тесты Playwright проверяют пользовательский поток в браузере. Обычные тесты не делают платных запросов к OpenAI. Отдельные команды перечислены в package.json.
Повторная сверка с оригинальными PDF, независимый расчёт 10 010 планов, проверка AI и интерфейса описаны в полном отчёте аудита.
Данные и интеграции
Исходные показатели пяти районов, десять индикаторов, четырнадцать мер, их эффекты и правила хранятся в src/data/. Это синтетический датасет для хакатона, а не актуальная городская статистика или прогноз. Пользователь выбирает меры из этого каталога; загрузки произвольного набора данных через интерфейс нет.
POST /api/analyze принимает { "decisions": [...] } и опционально полный массив replacementDecisions. Для обоих наборов сервер вызывает расчётный движок; неверный план возвращает HTTP 400. OpenAI Responses API используется только при наличии OPENAI_API_KEY. Ключ хранится в серверном окружении, а .env.local исключён из Git.
Лимит тела запроса — 16 КиБ (HTTP 413 при превышении). Тайм-аут OpenAI — 20 секунд, клиентского запроса — 25 секунд. Сбой или тайм-аут переключает объяснение на локальные проверенные факты; изменение плана отменяет устаревший запрос.
Развёрнутая версия
Публичная демо-версия: akim-na-5-chasov.daniiproger.chatgpt.site. Она доступна без API-ключа OpenAI и использует локальный анализ; расчёт сценариев и поиск замены работают на опубликованном сайте.
Авторы коммитов
История коммитов
- 2026-09-23 17:49Merge pull request #8 from BAITC-Hacks/audit/full-projectShek_Dan
- 2026-09-23 17:47docs: record verified audit revision and public demo smokeDaniil773-l
- 2026-09-23 17:46Merge remote-tracking branch 'origin/main' into audit/full-projectDaniil773-l
- 2026-09-23 17:46fix: harden AI analysis and validate simulator against original datasetDaniil773-l
- 2026-09-23 17:25docs: add public demo URLDaniil773-l
- 2026-09-23 17:08Update README.mdShek_Dan
- 2026-09-23 17:04docs: write jury-ready Russian project READMEDaniil773-l
- 2026-09-23 16:57docs: write jury-ready Russian project READMEDaniil773-l
Все коммиты (49)
- 2026-09-23 16:55Merge pull request #7 from BAITC-Hacks/integration/full-appShek_Dan
- 2026-09-23 16:50docs: record full integration acceptance resultsDaniil773-l
- 2026-09-23 16:48feat: integrate frontend, canonical engine and resilient AI analysisDaniil773-l
- 2026-09-23 16:28merge: integrate teammate frontendDaniil773-l
- 2026-09-23 16:27merge: integrate canonical simulation engineDaniil773-l
- 2026-09-23 16:27merge: integrate AI analysis implementationDaniil773-l
- 2026-09-23 16:15feat(frontend): upload city simulator projectArchmage
- 2026-09-23 15:45docs: clarify API demo while UI is pendingDaniil773-l
- 2026-09-23 15:41test: evaluate AI with real engine scenariosDaniil773-l
- 2026-09-23 15:41docs(engine): add README for calculation engine contributionAbdurrokhman Koblan
- 2026-09-23 15:30fix: ground AI analysis in verified scenario factsDaniil773-l
- 2026-09-23 15:21Complete simulation engine integration, reproducible build and team handoffAbdurrokhman Koblan
- 2026-09-23 15:15test: validate AI explanations against changed district dataDaniil773-l
- 2026-09-23 15:07Merge ENGINE-ADVISOR: exhaustive one-replacement search and stable strategy rankingsAbdurrokhman Koblan
- 2026-09-23 15:04chore: default city analysis to GPT-6 SolDaniil773-l
- 2026-09-23 15:03Merge ENGINE-EVALUATION: lagged effects, fixed synergies and verified district scoresAbdurrokhman Koblan
- 2026-09-23 15:00Merge ENGINE-VALIDATION: complete scenario validation and duplicate-conflict regressionAbdurrokhman Koblan
- 2026-09-23 14:59docs(engine): hand off advisor verificationAbdurrokhman Koblan
- 2026-09-23 14:57test(engine): cover negative-gain local optimumAbdurrokhman Koblan
- 2026-09-23 14:56fix: audit score formula and recalculate AI requestsDaniil773-l
- 2026-09-23 14:56docs(engine): record duplicate conflict regression checksAbdurrokhman Koblan
- 2026-09-23 14:56fix(engine): report certain local conflicts with duplicate measuresAbdurrokhman Koblan
- 2026-09-23 14:52Merge ENGINE-DATA: canonical TypeScript catalogs and independent data testsAbdurrokhman Koblan
- 2026-09-23 14:44test: verify API against real city scenariosDaniil773-l
- 2026-09-23 14:42docs(engine-evaluation): hand off formula and regression resultsAbdurrokhman Koblan
- 2026-09-23 14:41feat(engine-evaluation): calculate scores, effects and exact regressionsAbdurrokhman Koblan
- 2026-09-23 14:40feat(engine): add deterministic one-replacement advisorAbdurrokhman Koblan
- 2026-09-23 14:39docs(engine): hand off validation module and checksAbdurrokhman Koblan
- 2026-09-23 14:38docs(engine-data): record role handoffAbdurrokhman Koblan
- 2026-09-23 14:38test(engine-data): verify source data and baseline independentlyAbdurrokhman Koblan
- 2026-09-23 14:38feat(engine-data): add canonical measure dataAbdurrokhman Koblan
- 2026-09-23 14:38feat(engine-data): add canonical district dataAbdurrokhman Koblan
- 2026-09-23 14:38feat(engine-data): add canonical rules and catalogsAbdurrokhman Koblan
- 2026-09-23 14:37merge: integrate city simulation engineDaniil773-l
- 2026-09-23 14:37feat(engine): validate scenarios and cover negative casesAbdurrokhman Koblan
- 2026-09-23 14:30fix: let OpenAI SDK read API key from environmentDaniil773-l
- 2026-09-23 14:29chore(engine): freeze v2 TypeScript contract and parallel dispatchAbdurrokhman Koblan
- 2026-09-23 14:27feat: add client AI analysis integration hookDaniil773-l
- 2026-09-23 14:20feat: add AI scenario analysis with deterministic fallbackDaniil773-l
- 2026-09-23 14:05chore: initialize Next.js applicationDaniil773-l
- 2026-09-23 13:48feat(engine): add deterministic city simulation and validationAbdurrokhman Koblan
Структура репозитория (101 файлов)
.env.example .github/workflows/check.yml .gitignore AGENTS.md CLAUDE.md HANDOFF.md README.md docs/engine/README.md docs/engine/dispatch.json docs/engine/handoff.md docs/engine/handoffs/advisor.md docs/engine/handoffs/data.md docs/engine/handoffs/evaluation.md docs/engine/handoffs/validation.md docs/engine/integration-report.md docs/engine/parallel-contract.md docs/engine/sources/README.md docs/engine/sources/dataset-ru.txt docs/engine/sources/tz-extracted.txt docs/full-audit-report.md docs/integration-report.md e2e/frontend-audit.spec.ts e2e/simulator.spec.ts eslint.config.mjs next.config.ts package-lock.json package.json playwright.config.ts postcss.config.mjs public/file.svg public/globe.svg public/next.svg public/vercel.svg public/window.svg scripts/benchmark-engine.ts scripts/smoke-built.mjs scripts/test-engine.mjs scripts/write-browser-smoke.mjs src/app/api/analyze/route.test.ts src/app/api/analyze/route.ts src/app/favicon.ico src/app/globals.css src/app/layout.tsx src/app/page.tsx src/components/AIAnalysis.tsx src/components/AdvisorComparison.tsx src/components/BudgetBar.tsx src/components/DecisionSlot.tsx src/components/DistrictCard.tsx src/components/DistrictComparison.tsx src/components/ScenarioSummary.tsx src/data/districts.ts src/data/measures.ts src/data/rules.ts src/domain/evaluateScenario.ts src/domain/findBestReplacement.ts src/domain/index.ts src/domain/indicatorMath.ts src/domain/validateScenario.ts src/i18n.ts src/lib/ai/__fixtures__/changedDistrictScenario.ts src/lib/ai/__fixtures__/scenarioFixtures.ts src/lib/ai/analyze.test.ts src/lib/ai/analyze.ts src/lib/ai/engineScenario.test.ts src/lib/ai/engineScenario.ts src/lib/ai/fallbackAnalysis.test.ts src/lib/ai/fallbackAnalysis.ts src/lib/ai/liveEvaluation.test.ts src/lib/ai/qualityScenarios.test.ts src/lib/ai/requestScenarioAnalysis.test.ts src/lib/ai/requestScenarioAnalysis.ts src/lib/ai/schemas.ts src/lib/ai/useScenarioAnalysis.ts src/types/simulation.ts tests/contract-types.ts tests/engine/advisor.test.ts tests/engine/data.test.ts tests/engine/evaluation.test.ts tests/engine/pdf-oracle.test.ts tests/engine/validation.test.ts tests/reference/engine/README.md tests/reference/engine/cli.mjs tests/reference/engine/data.mjs tests/reference/engine/docs/contract.md tests/reference/engine/docs/handoff.md tests/reference/engine/examples/decisions.json tests/reference/engine/examples/result.json tests/reference/engine/index.d.mts tests/reference/engine/index.mjs tests/reference/engine/package.json tests/reference/engine/test/cli.test.mjs tests/reference/engine/test/data.test.mjs tests/reference/engine/test/engine.test.mjs tests/reference/engine/test/formula-audit.test.mjs tests/reference/engine/test/validator.test.mjs tests/simulation.test.ts tsconfig.engine.build.json tsconfig.engine.json tsconfig.json vitest.config.mts
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.