AAYMA
RU
Войти

QALA

Городской симулятор распределения бюджета: 5 решений по районам с лимитом 100, детерминированный результат на конец Q8, SVG-карта районов, календарь…

Рабочий MVP
Команда «SE G_YS» 5💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: SE G_YS
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Рабочий MVP

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

Суть

Городской симулятор распределения бюджета: 5 решений по районам с лимитом 100, детерминированный результат на конец Q8, SVG-карта районов, календарь лагов, история попыток и сравнение с глобальным оптимумом («What If»).

Как устроено

Черновик сценария проверяется FastAPI-пакетом draft-api без раскрытия Score. POST /api/scenarios/accept на Node-сервере считает детерминированный результат Q8. «What If» полным перебором проходит все 694 395 допустимых сценариев тем же валидатором и калькулятором и показывает глобальный максимум, результат кэшируется по версии модели. Есть подбор лучшей одиночной замены и разбор вклада решений по Шэпли. AI-разбор идёт через OpenAI Responses API со строгой JSON-схемой, каждый факт проверяется, при ошибке остаётся базовый разбор. Интерфейс на ru/kk, история попыток в localStorage.

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

  • полный перебор сценариев
  • Shapley value (вклад решений)
  • best single replacement
  • OpenAI Responses API strict JSON schema
  • проверка фактов AI-ответа
  • кэширование по версии модели

Метрики

Холодный полный перебор 694 395 допустимых сценариев ≈ 11.2 с

Особенности

Сравнение с глобальным оптимумом полным перебором и разложение вклада решений по Шэпли дают игроку объективную точку отсчёта. Разработка шла по PRD и issue-driven TDD с Codex-скиллами в .agents/skills.

Стек

Node.js · FastAPI · Python · uv · Vite · React · TypeScript · Docker

Модели

OpenAI gpt-4o-mini


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

README

README.md

hack-78afec8c-se-g-ys

Hackathon team repository for SE G_YS

Локальный запуск

QALA показывает исходные данные пяти районов и каталог 14 мероприятий, а затем позволяет собрать и проверить черновик сценария. Проверка не раскрывает Score.

Один раз установите зависимости:

uv sync --locked --project packages/draft-api
npm ci --prefix packages/draft-ui
npm start

Откройте http://127.0.0.1:5173. Скрипт запускает FastAPI на порту 8013 и Vite на порту 5173; Vite передаёт запросы /api в FastAPI.

Запуск в Docker

Для запуска полной текущей веб-версии достаточно Docker: образ содержит Node-сервер QALA и не требует установки зависимостей на хосте.

docker build --tag qala .
docker run --rm --name qala --publish 3000:3000 qala

Откройте http://127.0.0.1:3000. Чтобы использовать AI-разбор, передайте серверный ключ при запуске, например docker run --rm --publish 3000:3000 --env OPENAI_API_KEY qala. Не добавляйте ключ в образ или репозиторий.

Проверка:

npm test
uv run --project packages/draft-api pytest
npm test --prefix packages/draft-ui

Каталог доступен через GET /api/catalog, а проверка черновика — через POST /api/drafts/validate.

Принятие сценария выполняется через POST /api/scenarios/accept с JSON-полем decisions из пяти решений. Сервер возвращает причины отказа без результата для невалидного набора и детерминированный результат Q8 для принятого сценария.

После принятия браузер сохраняет неизменяемую попытку в localStorage. История доступна только в том же браузере: из неё можно открыть результат, создать редактируемую копию с тем же лимитом 100 или сравнить любые две попытки по решениям, расходам, Score и изменениям показателей районов.

Phase 2: карта, лаги и What If

После принятия сценария доступна проектная SVG-карта пяти синтетических районов. Район можно выбрать мышью или клавиатурой; рядом всегда есть текстовое описание исходных и, после принятия, Q8-показателей и решений. Цвет и геометрия не являются единственным источником данных. В черновике карта показывает только выбранные решения, их охват и стоимость — Score и значения Q8 не раскрываются.

Принятый сценарий также получает календарь лагов с пятью строками и Q1–Q8. Маркер обозначает начало действия мероприятия; это не поквартальная симуляция и не содержит промежуточных Score или показателей. Весь результат относится к концу Q8.

Кнопка What If: сравнить с глобальным максимумом появляется только у принятой попытки и запускается только по явному нажатию. Сервер перебирает все допустимые неупорядоченные сценарии активного каталога, используя тот же валидатор и калькулятор, затем показывает Score, разницу, пять решений и стоимость стабильного представителя. Равные максимумы выбираются по меньшей стоимости, затем по каноническому порядку идентификаторов и районов. Результат сохраняется с попыткой; он относится исключительно к синтетическому каталогу и формуле и не является рекомендацией реальной городской политики.

Измерение глобального поиска

Повторяемая команда для холодного измерения:

time node --test test/issue12-global-comparison.test.js

На текущем ноутбуке разработки (2026-09-23) сам холодный перебор 694 395 допустимых сценариев занял примерно 11.2 с. Сервер кеширует результат только пока его вычисленная версия модели совпадает с текущими данными и формулой; изменение каталога или модели создаёт другую версию и не использует старый ответ. Для демонстрационного ноутбука измерение следует повторить этой же командой.

AI-разбор OpenAI

После принятия браузер сразу сохраняет расчётный результат и базовый разбор, затем асинхронно вызывает POST /api/scenarios/analyze с теми же решениями. Сервер пересчитывает результат, отправляет только рассчитанные факты в OpenAI Responses API со строгой JSON-схемой и проверяет каждый факт, обоснование и точечную замену перед показом AI-разбора. Ошибка сети, тайм-аут или некорректный ответ оставляют доступным явно обозначенный базовый разбор; кнопка «Повторить AI-разбор» не создаёт новую попытку.

Для живого вызова задайте серверные переменные окружения перед запуском:

export OPENAI_API_KEY='...'
export OPENAI_MODEL='gpt-4o-mini' # необязательно
export OPENAI_TIMEOUT_MS=12000    # необязательно
npm start

Ключ не передаётся браузеру и не сохраняется в localStorage. Без OPENAI_API_KEY приложение продолжает работать с базовым разбором.

The cached API at POST /api/attempts/:attemptId/analysis returns one verified AI version per attempt and locale (ru or kk), deduplicating concurrent requests and falling back to the localized basic analysis on failure.

Звёзды
⭐ 0
Форки
0
Язык
JavaScript
Последний push
в прошлом месяце
Коммиты
38
Авторы
3
Файлы
84
Ветки
15

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

Yertugan06 16Tamerlan Yessimov 12sulte4 10

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

  • 2026-09-23 18:02chore: add Docker run workflowsulte4
  • 2026-09-23 17:46feat: add Shapley impact breakdownsulte4
  • 2026-09-23 17:44merge: block invalid scenario acceptanceYertugan06
  • 2026-09-23 17:41feat: retain global comparison historysulte4
  • 2026-09-23 17:38feat: add global What If comparisonsulte4
  • 2026-09-23 17:35feat: block invalid scenario acceptanceTamerlan Yessimov
  • 2026-09-23 17:33feat: add Q1-Q8 lag calendar for accepted scenariosTamerlan Yessimov
  • 2026-09-23 17:33feat: persist global comparisons in historysulte4
Все коммиты (38)
  • 2026-09-23 17:31Implement Phase 2 visual analysis and global comparisonYertugan06
  • 2026-09-23 17:21chore: prdYertugan06
  • 2026-09-23 17:20Merge remote-tracking branch 'origin/feature/issue-10-bilingual-ai'Yertugan06
  • 2026-09-23 17:14merge: prevent budget overspending in draftsYertugan06
  • 2026-09-23 17:12merge: add verified OpenAI scenario analysisYertugan06
  • 2026-09-23 17:08chore: ignore local OpenAI environmentYertugan06
  • 2026-09-23 17:06feat: add bilingual cached AI analysesTamerlan Yessimov
  • 2026-09-23 17:04feat: add verified OpenAI scenario analysisYertugan06
  • 2026-09-23 17:02Merge branch 'feat/issue-9'Yertugan06
  • 2026-09-23 17:00feat: prevent budget overspending in draftsTamerlan Yessimov
  • 2026-09-23 16:55feat: add accessible district scenario mapsulte4
  • 2026-09-23 16:55include calculated facts and basic analysisTamerlan Yessimov
  • 2026-09-23 16:54merge history into localized issue baseTamerlan Yessimov
  • 2026-09-23 16:54Merge branch 'feat/issue-8-history'Yertugan06
  • 2026-09-23 16:52feat: localize QALA in Kazakhsulte4
  • 2026-09-23 16:49feat: save and compare accepted attemptssulte4
  • 2026-09-23 16:47feat: add calculated facts and basic analysisYertugan06
  • 2026-09-23 16:44Merge remote-tracking branch 'origin/main' into feat/issue-9sulte4
  • 2026-09-23 16:39Merge branch 'feature/issue-4-5-merged'Yertugan06
  • 2026-09-23 16:32Merge branch 'feature/issue-4-q8-result' into feature/issue-5-recommendationTamerlan Yessimov
  • 2026-09-23 16:30feat: combine catalog and draft editorsulte4
  • 2026-09-23 16:28chore: localize recommendation fallbackTamerlan Yessimov
  • 2026-09-23 16:27feat: recommend best single replacementTamerlan Yessimov
  • 2026-09-23 16:25feat: accept scenarios and calculate deterministic Q8 resultTamerlan Yessimov
  • 2026-09-23 16:24feat: accept scenarios and calculate deterministic Q8 resultTamerlan Yessimov
  • 2026-09-23 16:01feat: add initial city and event catalog pathTamerlan Yessimov
  • 2026-09-23 15:28chore : prdYertugan06
  • 2026-09-23 14:45chore: context processYertugan06
  • 2026-09-23 11:35Make skill cross-references portable to CodexYertugan06
  • 2026-09-23 11:29Add Codex-compatible skills under .agents/skillsYertugan06
Структура репозитория (84 файлов)
.agents/skills/grill-with-docs/ADR-FORMAT.md
.agents/skills/grill-with-docs/CONTEXT-FORMAT.md
.agents/skills/grill-with-docs/SKILL.md
.agents/skills/implement/SKILL.md
.agents/skills/implement/agents/openai.yaml
.agents/skills/improve-codebase-architecture/DEEPENING.md
.agents/skills/improve-codebase-architecture/HTML-REPORT.md
.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md
.agents/skills/improve-codebase-architecture/LANGUAGE.md
.agents/skills/improve-codebase-architecture/SKILL.md
.agents/skills/prototype/LOGIC.md
.agents/skills/prototype/SKILL.md
.agents/skills/prototype/UI.md
.agents/skills/resolving-merge-conflicts/SKILL.md
.agents/skills/tdd/SKILL.md
.agents/skills/tdd/deep-modules.md
.agents/skills/tdd/interface-design.md
.agents/skills/tdd/mocking.md
.agents/skills/tdd/refactoring.md
.agents/skills/tdd/tests.md
.agents/skills/to-issues/SKILL.md
.agents/skills/to-prd/SKILL.md
.dockerignore
.gitignore
CONTEXT.md
Dockerfile
README.md
Requirements.md
dataset.md
docs/PLAN.md
docs/PRD-phase-2.md
docs/PRD-phase-3.md
docs/PRD.md
package.json
packages/draft-api/.gitignore
packages/draft-api/README.md
packages/draft-api/examples/app.py
packages/draft-api/examples/catalog.json
packages/draft-api/pyproject.toml
packages/draft-api/src/qala_draft/__init__.py
packages/draft-api/src/qala_draft/api.py
packages/draft-api/src/qala_draft/core.py
packages/draft-api/tests/conftest.py
packages/draft-api/tests/test_contract.py
packages/draft-api/tests/test_draft_api.py
packages/draft-api/uv.lock
packages/draft-ui/.gitignore
packages/draft-ui/README.md
packages/draft-ui/demo/main.tsx
packages/draft-ui/demo/style.css
packages/draft-ui/index.html
packages/draft-ui/package-lock.json
packages/draft-ui/package.json
packages/draft-ui/src/DraftEditor.tsx
packages/draft-ui/src/client.ts
packages/draft-ui/src/index.ts
packages/draft-ui/src/messages.ts
packages/draft-ui/src/style.css
packages/draft-ui/src/types.ts
packages/draft-ui/tests/DraftEditor.test.tsx
packages/draft-ui/tests/server.ts
packages/draft-ui/tests/setup.ts
packages/draft-ui/tsconfig.json
packages/draft-ui/vite.config.ts
public/client.js
public/history.js
run.sh
server.js
src/ai-analysis.js
src/data.js
src/i18n.js
src/openai-analysis-provider.js
src/simulation.js
src/view.js
test/catalog.test.js
test/issue10-ai-analysis.test.js
test/issue11-budget.test.js
test/issue12-global-comparison.test.js
test/issue19-acceptance.test.js
test/issue4-scenario.test.js
test/issue6-basic-analysis.test.js
test/issue7-ai-analysis.test.js
test/issue8-history.test.js
test/issue9-localization.test.js
Ветки (15)

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

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

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