AAYMA
RU
Войти

QalaMind

Streamlit-симулятор: 5 мер из 14 с назначением районов, проверка ограничений, расчёт Score города и районов до и после, объяснение результата…

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

О проекте

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

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

Суть

Streamlit-симулятор: 5 мер из 14 с назначением районов, проверка ограничений, расчёт Score города и районов до и после, объяснение результата (OpenAI, NVIDIA или автономная сводка).

Как устроено

Данные о районах и мерах лежат в локальных JSON. engine/simulator.py (validate_scenario, simulate) считает эффект с лагом (8−L)/8 и бонусами сочетаний, затем Score = 0.7·D_avg + 0.3·min(D) − N_crit. generate_debrief не генерирует свободный текст: модель выбирает по одной формулировке из вариантов, заранее собранных Python. Ответ проверяется по структуре и списку допустимых фраз, есть кеш сессии и автономный фолбэк.

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

  • deterministic scoring engine
  • constrained choice from pre-generated options
  • OpenAI Responses API structured output
  • session cache

Метрики

Пример жюри: Score 52.56 → 56.54 (+3.99), 95/100 бюджета, критических показателей 0

Особенности

Предельно строгая защита от галлюцинаций: LLM только выбирает одну из формулировок, собранных Python, и ответ проверяется на совпадение с допустимыми вариантами.

Стек

Python · Streamlit · Pydantic · pandas · python-dotenv · unittest

Модели

OpenAI gpt-6-sol · NVIDIA mistralai/mistral-nemotron


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

README

README.md

QalaMind

Симулятор городских решений для Астаны. Проект для кейса «Аким на 5 часов» на HackAlem AI 2026.

Краткое описание

Как распределить ограниченный бюджет между школами, транспортом, экологией, безопасностью и городскими сервисами? QalaMind позволяет выбрать пять мер и увидеть, как по модели кейса изменятся показатели качества жизни в районах Астаны.

Приложение рассчитано на участников и жюри хакатона, а также на тех, кто хочет разобраться в компромиссах городского управления. Это учебный симулятор на фиксированных данных: его результаты описывают заданную модель, а не прогнозируют реальные изменения в городе.

Для демонстрации не нужны API-ключи: расчёты и автономное объяснение работают локально после установки зависимостей.

Что реализовано

  • Выбор пяти решений из каталога 14 мер по пяти направлениям. Для районной меры пользователь выбирает район; общегородская применяется ко всем районам.
  • Проверка ограничений при каждом изменении: бюджет до 100 условных единиц, ровно пять решений, отсутствие повторов, не более двух мер одного направления, корректное назначение районов и совместимость мер. Ошибки показаны рядом с выбором; неверный сценарий нельзя рассчитать.
  • Закреплённая панель с количеством решений, стоимостью и остатком бюджета. При прокрутке она плавно становится компактнее.
  • Расчёт результата: итоговая оценка города и её изменение, самый слабый район, количество критических показателей, таблица районных оценок до и после решений.
  • Понятные названия показателей в предупреждениях и объяснениях, справочник показателей и группировка выбранных мер по направлениям.
  • Три источника объяснения: OpenAI, NVIDIA или автономная сводка. Ответ содержит разделы «Почему изменился балл», «Главный риск» и «Рекомендация».
  • Готовый пример и очистка выбора. Любое изменение решения убирает прежний результат и объяснение, чтобы они не относились к устаревшему сценарию.
  • Защита от лишних API-запросов: объяснение запрашивается отдельной кнопкой, повторный запрос с теми же фактами, провайдером и моделью использует кэш текущей сессии. При сбое выбранного провайдера приложение выдаёт автономную сводку и показывает фактический источник.

Как работает решение

  1. При открытии приложение загружает локальные данные и подставляет пример из пяти мер. Автоматического расчёта или обращения к AI нет.
  2. Пользователь меняет меры и районы. Стоимость, остаток бюджета и сообщения об ошибках обновляются сразу.
  3. Кнопка «Рассчитать сценарий» запускает проверку и расчёт на Python.
  4. Пользователь изучает итоговую оценку, слабый район, критические показатели и сравнение районов.
  5. В разделе «Объяснение результата» выбирает источник и нажимает «Получить объяснение».

Расчёт охватывает 8 кварталов. Эффект меры с задержкой L умножается на (8 − L) / 8. Затем прибавляются предусмотренные сочетаниями мер бонусы, а значения показателей ограничиваются диапазоном от 0 до 100. Бонусы сочетаний мер не уменьшаются из-за задержки.

Районная оценка — взвешенная сумма десяти показателей. Итоговая оценка города учитывает среднюю оценку с весами населения, самый слабый район и число критических показателей:

Score = 0.7 × D_avg + 0.3 × min(D_d) − N_crit

Здесь D_avg — средняя районная оценка с весами населения, D_d — оценка отдельного района, а N_crit — количество пар «район — показатель» со значением строго ниже 40. Неиспользованный бюджет не даёт дополнительных баллов. Полные формулы и ограничения описаны в AGENTS.md.

Все числа рассчитывает Python. В текущей версии модель выбирает по одной готовой формулировке для каждого раздела объяснения из вариантов, сформированных Python по результату. Ответ проходит проверку структуры и совпадения с допустимыми формулировками. Свободная генерация советов не реализована.

Технологии

КомпонентТехнология и назначение
ЯзыкPython 3.10+ — проверка сценариев, вычисления и логика приложения
ИнтерфейсStreamlit 1.52+ — формы, таблицы, показатели и состояние сессии
ВалидацияPydantic 2 — модели данных, сценариев, результатов и объяснений
Табличные данныеpandas — зависимость для работы с таблицами, в том числе в тестах интерфейса
Настройкиpython-dotenv — чтение локального файла .env
OpenAISDK openai>=3.17,<4, Responses API со структурированным ответом; модель по умолчанию — gpt-6-sol, уровень reasoning — low
NVIDIAChat Completions API через тот же SDK; модель по умолчанию — mistralai/mistral-nemotron
ОформлениеЛокальные HTML, CSS и JavaScript — закрепление и анимация панели бюджета
Проверкиunittest, unittest.mock, Streamlit AppTest

Модели задаются в конфигурации. Наличие модели в настройках не гарантирует доступ к ней в конкретном аккаунте провайдера.

Архитектура проекта

app.py                     Интерфейс, состояние выбора и кнопки действий
engine/
├── models.py              Контракты данных и числовые правила модели
├── simulator.py           Загрузка данных, проверка сценария и расчёты
├── advisor.py             OpenAI, NVIDIA, кэш и автономное объяснение
└── labels.py              Русские названия показателей
data/
├── districts.json         Исходные показатели и веса населения районов
├── measures.json          Меры, стоимость, задержки, эффекты и совместимость
└── mock_debrief.json      Шаблоны автономной сводки
assets/
└── summary_header.html    Оформление и анимация закреплённой панели
.streamlit/config.toml     Светлая тема приложения
tests/
├── test_simulator.py      Формулы, данные и ограничения
├── test_advisor.py        Провайдеры, проверка ответов и резервный режим
└── test_app.py            Пользовательский сценарий и границы API-вызовов
.env.example               Шаблон настроек без ключей
requirements.txt           Зависимости
AGENTS.md                  Спецификация и правила проекта

Поток данных: локальные JSON → проверка выбора → расчёт на Python → результат в интерфейсе → объяснение по запросу.

Модуль расчётов не зависит от Streamlit или клиентов AI. Его основные функции — load_dataset, validate_scenario и simulate. Результат содержит изменения показателей, прямой вклад каждой меры, отдельные бонусы сочетаний мер и поправки из-за границ шкалы. Функция generate_debrief получает готовый результат и не изменяет его числа.

JavaScript управляет только видом панели бюджета. Вычислений городской модели в браузере нет.

Установка и запуск

Нужны Python 3.10+ и Git. Интернет требуется для первоначальной установки зависимостей и, при использовании AI-провайдера, для запроса объяснения.

1. Скачайте проект

git clone https://github.com/BAITC-Hacks/hack-b5cf38a5-abzhurd qalamind
cd qalamind

2. Создайте окружение и установите зависимости

Для macOS и Linux:

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .env

Для Windows PowerShell:

py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
Copy-Item .env.example .env

Копировать шаблон нужно только при первом запуске. Если .env уже есть, отредактируйте его, сохранив свои настройки.

3. Выберите режим

Для демонстрации без API-ключей установите в .env:

ADVISOR_PROVIDER=offline
MOCK_MODE=true

Для объяснения через OpenAI или NVIDIA установите MOCK_MODE=false, выберите провайдера и добавьте его ключ. Доступные настройки:

ПеременнаяНазначение
ADVISOR_PROVIDERopenai, nvidia или offline; в шаблоне — openai
MOCK_MODEtrue принудительно включает автономный режим и блокирует переключение провайдера в интерфейсе
OPENAI_API_KEYКлюч для OpenAI
NVIDIA_API_KEYКлюч для NVIDIA
OPENAI_MODELМодель OpenAI, по умолчанию gpt-6-sol
OPENAI_REASONING_EFFORTУровень reasoning OpenAI, по умолчанию low
NVIDIA_MODELМодель NVIDIA, по умолчанию mistralai/mistral-nemotron
ADVISOR_MAX_OUTPUT_TOKENSЛимит ответа, по умолчанию и максимум — 700

Файл .env исключён из Git. Полей для ввода ключей в интерфейсе нет.

4. Запустите приложение

Для macOS и Linux:

.venv/bin/python -m streamlit run app.py

Для Windows PowerShell:

.\.venv\Scripts\python.exe -m streamlit run app.py

Откройте адрес, который напечатает Streamlit, обычно http://localhost:8501.

После изменения .env остановите сервер сочетанием Ctrl+C, запустите его снова и обновите страницу. Переменные окружения процесса имеют приоритет над .env: запуск с MOCK_MODE=true в командной строке принудительно оставит приложение в автономном режиме.

Как проверить решение

Сценарий для жюри

Запустите приложение в автономном режиме и нажмите «Загрузить пример». В строках будут выбраны:

МераРайон или территорияСтоимость
M7 — Школа + детсадНура24
M8 — Центр семейного здоровья / поликлиникаНура20
M10 — Освещение и камерыНура12
M12 — Единая цифровая платформа обращенийВесь город14
M5 — Перевод частного сектора на чистое топливоСарыарка25

Нажмите «Рассчитать сценарий» и сравните результат:

ПоказательОжидаемое значение
Исходная оценка города52.56
Итоговая оценка города56.54
Изменение+3.99
Потрачено95 из 100
Остаток бюджета5
Самый слабый районНура
Оценка Нуры после решений52.96
Критических показателей после решений0

Числа округляются только при отображении. Например, изменение считается из исходных значений 56.54307 − 52.55768, поэтому отображается как +3.99.

Затем проверьте поведение приложения:

  1. Нажмите «Получить объяснение». Появятся три раздела и отметка «Автономная сводка».
  2. Измените район у любой районной меры. Предыдущие результат и объяснение исчезнут; для нового выбора потребуется новый расчёт.
  3. Загрузите пример снова и во второй строке выберите M7 вместо M8. Повтор меры будет отмечен ошибкой, кнопка расчёта станет недоступной. Стоимость при этом будет 99: повторная строка учитывается в бюджете, хотя сценарий недопустим.
  4. Нажмите «Очистить выбор». Останутся пять пустых строк; рассчитать их нельзя.

При настроенном API повторите запрос объяснения с OpenAI или NVIDIA. Если запрос не удался, интерфейс должен показать автономную сводку с соответствующей отметкой.

Автоматические проверки

На macOS и Linux:

.venv/bin/python -m unittest discover -s tests -v

На Windows:

.\.venv\Scripts\python.exe -m unittest discover -s tests -v

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

Полный перебор районных назначений включается отдельно; по умолчанию этот длительный тест пропускается:

SIMULATOR_EXHAUSTIVE=1 .venv/bin/python -m unittest tests.test_simulator -v

Данные и интеграции

Числовая основа проекта — данные конкурсного кейса, сохранённые в репозитории:

  • data/districts.json: пять районов — Есиль, Алматы, Сарыарка, Байконур и Нура; по десять исходных показателей и вес населения для каждого.
  • data/measures.json: 14 мер по направлениям «Транспорт», «Экология», «Соцсфера», «Безопасность» и «Сервисы», их стоимость, задержки, эффекты, бонусы сочетаний и несовместимости.
  • data/mock_debrief.json: шаблоны автономного объяснения, которые заполняются результатами расчёта.
  • engine/models.py: веса показателей и числовые ограничения, перенесённые из спецификации в AGENTS.md.

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

Внешние API используются только для объяснения по отдельному действию пользователя:

ПровайдерИнтеграция
OpenAIResponses API со структурированным ответом
NVIDIAChat Completions API: https://integrate.api.nvidia.com/v1

Провайдер получает рассчитанные факты сценария и допустимые формулировки объяснения. Для одного запроса установлен тайм-аут до 20 секунд, автоматические повторы отключены. Ошибка, отсутствие ключа или неподходящий ответ приводят к автономной сводке; другой платный провайдер автоматически не вызывается.

Ограничения

  • Модель использует фиксированные данные и правила кейса. Стоимость задана в условных единицах; реальная оценка бюджета и прогноз городской ситуации не выполняются.
  • AI выбирает готовые подтверждённые формулировки. Свободный диалог, поиск оптимального набора мер и генерация новых мер не реализованы.
  • Доступность моделей и условия оплаты зависят от аккаунта провайдера. Автоматические тесты не проверяют реальную авторизацию или доступ к платному API.
  • Нет графиков, тепловой карты показателей, отдельного сравнения нескольких сценариев и дополнительных пресетов.
  • Нет кнопки экспорта полного расчёта в JSON, сохранения истории сценариев или запуска через run.sh.
  • Выбор, результат и кэш хранятся в сессии Streamlit. Постоянное хранилище сценариев не реализовано.
  • Закрепление панели использует структуру страницы Streamlit; после обновления фреймворка оформление стоит перепроверить.

Развёрнутая версия

Публичная ссылка на развёрнутое приложение в репозитории не указана. Для проверки используйте локальный запуск из раздела «Установка и запуск».

Адрес http://localhost:8501 доступен на компьютере, где запущен Streamlit, и не является публичной демоверсией.

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

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

poizon 10

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

  • 2026-09-23 17:41Rewrite README in Russian for hackathon judgespoizon
  • 2026-09-23 17:34Add compact sticky summary and QalaMind brandingpoizon
  • 2026-09-23 17:18Improve user-facing indicator explanationspoizon
  • 2026-09-23 16:53Build Streamlit scenario flowpoizon
  • 2026-09-23 16:12Add dual-provider advisor with grounded offline fallbackpoizon
  • 2026-09-23 15:36Implement deterministic city simulator and testspoizon
  • 2026-09-23 14:58docs: make repository sources authoritativepoizon
  • 2026-09-23 14:41feat(iteration-2): add deterministic data and typed contractspoizon
Все коммиты (10)
  • 2026-09-23 14:25docs: align project governance with hackathon specificationpoizon
  • 2026-09-23 13:52feat(hour-1): project scaffolding, data models, and simulator architecturepoizon
Структура репозитория (20 файлов)
.env.example
.gitignore
.streamlit/config.toml
AGENTS.md
README.md
app.py
assets/summary_header.html
data/districts.json
data/measures.json
data/mock_debrief.json
engine/__init__.py
engine/advisor.py
engine/labels.py
engine/models.py
engine/simulator.py
requirements.txt
tests/__init__.py
tests/test_advisor.py
tests/test_app.py
tests/test_simulator.py

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

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

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