AAYMA
RU
Войти

Граф денег (TayMas Solutions)

Рабочее место AML-аналитика: загрузка трёх Parquet, граф переводов с объяснимыми ролями, Louvain-кластерами и топ-30 очередью проверки…

Доведённый продукт
Команда «TayMas Solutions» 35💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: TayMas Solutions
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт

Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)

Суть

Рабочее место AML-аналитика: загрузка трёх Parquet, граф переводов с объяснимыми ролями, Louvain-кластерами и топ-30 очередью проверки, интерактивный граф на Cytoscape.js, AML Copilot с проверкой фактов и «дело расследования» с экспортом.

Как устроено

Python-пайплайн money_graph валидирует данные и строит направленный граф; считаются потоки, PageRank, betweenness, HITS, достижимость, циклы до 5 узлов и временная близость переводов. Роли назначаются правилами с rule-кодом и evidence, Louvain с проверкой устойчивости, priority_score по объяснимой формуле с поправкой на границу выгрузки, анализ устойчивости сети при удалении топ-узлов. Copilot через 9 read-only инструментов и верификатор сверяет утверждения с CSV, NVIDIA API с function calling подключается опционально.

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

  • NetworkX
  • PageRank
  • betweenness
  • HITS
  • Louvain
  • поиск циклов
  • rule-based роли
  • resilience при удалении топ-N
  • function calling
  • evidence verifier
  • Cytoscape.js

Особенности

Командная разработка через задачи PAN-xx и PR; версионирование наборов данных с SHA-256 и отчётами о прогоне; панель «Каких данных не хватает?» и кейс-бук расследования с экспортом JSON/HTML; e2e-тесты на Playwright.

Стек

Python · pandas · NumPy · SciPy · PyArrow · NetworkX · React · TypeScript · Vite · Cytoscape.js · Docker Compose · nginx · pytest · Vitest · Playwright

Модели

NVIDIA Chat Completions API (модель через NVIDIA_MODEL)


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

README

README.md

HackAlem AI — «Граф денег»

TayMas Solutions · рабочее место AML-аналитика для исследования сети переводов.

Проект помогает специалисту по противодействию отмыванию денег (AML) разобраться в связях между клиентами: увидеть сбор и распределение средств, выбрать узлы для первоочередной проверки и сохранить основания своей гипотезы. На вход поступает обезличенная выгрузка внутрибанковских переводов; на выходе — граф, объяснимые роли клиентов, кластеры, очередь проверки и материалы расследования.

Роли и приоритеты рассчитываются локально по правилам и графовым признакам. Copilot помогает исследовать готовые результаты и показывает источники утверждений. Основной сценарий работает без внешней AI-модели и API-ключа.

Результат анализа — гипотеза для дальнейшей проверки. Приоритет не является вероятностью нарушения, а проверка фактов по CSV не доказывает виновность клиента.

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

  • Обработка и проверка данных. Загрузка трёх Parquet-файлов через браузер или CLI, проверка полей, типов, идентификаторов и согласованности сумм и количества операций между рёбрами и транзакциями. Новый набор становится активным после успешного расчёта; при ошибке предыдущий граф сохраняется.
  • Графовая аналитика. Входящие и исходящие потоки, число контрагентов, PageRank, betweenness, HITS, достижимость, циклы длиной до пяти узлов и временная близость переводов.
  • Объяснимые роли. Каждый узел получает роль, role_score, код правила и текстовое основание evidence.
  • Кластеры и очередь проверки. Кластеризация Louvain с проверкой устойчивости, сводки по сообществам и топ-30 по priority_score. Вклад составляющих приоритета сохраняется в CSV.
  • Интерактивный граф. Поиск по GID, фильтры по роли, кластеру, глубине и seed-статусу, просмотр соседей, направлений и сумм переводов, карточка клиента, режимы «Потоки» и «Сеть», окраска по роли или кластеру.
  • AML Investigation Copilot. Объяснение роли и приоритета, поиск общего сборщика, обход связей вверх и вниз, предложение следующего шага. Структурированные факты сверяются с CSV на сервере и в браузере; узлы и связи из проверенного ответа подсвечиваются на графе.
  • План недостающих данных. Панель «Каких данных не хватает?» предлагает запросить выписку, начальный остаток либо точное время операций и объясняет, как это поможет проверить гипотезу. План формируется локально; запросы в банк не отправляются.
  • Дело расследования. Сохранение снимков узлов и ответов Copilot, гипотезы и заметок в браузере; импорт и экспорт JSON; экспорт HTML-справки для печати или сохранения в PDF средствами браузера. Снимки другой версии данных получают отдельную отметку.
  • Контроль результатов. Проверки выходных таблиц, аудит топ-листа, отчёты о прогоне, SHA-256 файлов и повторный расчёт для проверки воспроизводимости.

В решении используются шесть ролей:

Роль в CSVСмысл гипотезы
coordinatorКоординирует сбор и распределение средств
consolidatorСобирает средства от нескольких плательщиков
distributorРаспределяет средства множеству получателей
transitИмеет признаки передачи поступивших средств дальше
terminalУдерживает значительную долю видимых поступлений при наблюдаемом исходящем потоке
peripheralНе достигает порогов других ролей либо имеет недостаточно наблюдаемых данных

Пороги и порядок правил находятся в money_graph/config.py и money_graph/roles.py. role_score отражает силу правил, а не статистически откалиброванную вероятность.

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

  1. Аналитик выбирает nodes.parquet, edges.parquet и transactions.parquet в браузере и нажимает «Построить граф». Для отдельного CLI-прогона файлы размещаются в data/.
  2. Python-пайплайн проверяет данные и строит направленный граф: клиент — узел, агрегированный перевод от плательщика к получателю — ребро.
  3. Для узлов рассчитываются признаки и роли. Затем выделяются кластеры, рассчитываются приоритеты и формируется очередь проверки.
  4. После проверки результатов API публикует новую версию CSV и снимок Copilot, а интерфейс открывает граф. Выбранные ранее GID и ответы сбрасываются; ручной перезапуск не нужен. CLI записывает результаты отдельно в out/.
  5. Аналитик изучает карточку и связи, задаёт вопрос Copilot и сверяет основания ответа с указанными источниками в CSV.
  6. Нужные узлы и ответы сохраняются в дело вместе с гипотезой, заметками и планом дальнейшей проверки. Материалы можно выгрузить в JSON или печатную справку.
Файл результатаСодержание
nodes_roles.csvУзлы, роли, role_score, кластеры, приоритеты, основания и признаки
clusters.csvРазмер кластеров, внутренний оборот, ключевые узлы и гипотезы
top_nodes.csvОчередь проверки: rank, gid, role, priority_score, why
edge_table.csvНаправленные связи, суммы, число операций, даты и доли потоков
run_report.md, run_report.jsonПроверки, предупреждения, время этапов, версии библиотек и хеши CSV

Три обязательных CSV доступны по ссылкам «Скачать CSV» под формой загрузки. Браузерные версии хранятся в рабочем каталоге API, CLI-выгрузки — в out/; эти наборы не перезаписывают друг друга.

Формула приоритета учитывает сбор, рассылку, характер потока, связи с seed-клиентами, связи между кластерами и объём переводов. Для границы выгрузки применяется поправка. Подробности: признаки, кластеры, приоритет, топ-лист.

Технологии

СлойТехнологии и назначение
АналитикаPython 3.11+, pandas, NumPy, SciPy, PyArrow для Parquet, NetworkX 3.6.1 для графов
ИнтерфейсTypeScript, React 19, Vite 7, Cytoscape.js, CSS
Локальный APIСтандартная библиотека Python: HTTP-сервер, JSON-контракты, инструменты чтения графа и верификатор
Опциональный AINVIDIA Chat Completions API с вызовом функций; HTTPS-клиент на стандартной библиотеке Python
ХранениеParquet на входе, CSV и отчёты на выходе; localStorage для текущего дела, JSON и HTML для экспорта
ЗапускPowerShell/CMD, Bash, Docker Compose, nginx
Проверкиpytest; Vitest и Testing Library; Playwright для браузерных сценариев

Зависимости: requirements.txt, frontend/package.json, frontend/package-lock.json.

AI-модель в коде не зафиксирована: её идентификатор задаётся через NVIDIA_MODEL. Адаптер рассчитан на модель с поддержкой вызова функций. Обучения собственной модели в репозитории нет; роли, кластеры и приоритеты рассчитываются без LLM.

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

flowchart TD
    UPLOAD["Браузер: три Parquet"] --> JOB["Локальный API: каталог задания"]
    JOB --> PIPE["money_graph: проверка, граф, признаки, роли"]
    DATA["CLI: data/*.parquet"] --> PIPE
    PIPE --> ANALYTICS["analytics: кластеры, приоритет, топ-лист"]
    ANALYTICS --> OUT["Проверенные CSV и отчёты"]
    OUT --> SNAP["Версия набора: CSV + снимок Copilot"]
    SNAP --> UI["React + Cytoscape.js"]
    OUT --> TOOLS["agent_tools: чтение графа и проверка фактов"]
    UI <-->|"/api/copilot"| API["agent_orchestrator: сценарий и ответ"]
    API <--> TOOLS
    API -.->|"по явному запросу"| NVIDIA["NVIDIA API"]
    UI --> CASE["Дело: localStorage, JSON, HTML"]
КаталогОтветственность
money_graph/Основной пайплайн, роли, входные и выходные схемы, CLI, отчёты
analytics/Кластеры, приоритеты, аудит топ-листа; дополнительные модули сравнения приоритетов и устойчивости графа
agent_tools/Девять инструментов чтения готовых выгрузок, проверка утверждений и контрольные вопросы
agent_orchestrator/Загрузка Parquet, версии наборов, HTTP API, маршрутизация вопроса, ограниченный план вызовов, сборка ответа и адаптер NVIDIA
frontend/Граф, карточки, Copilot, план недостающих данных и дело расследования
scripts/, deploy/Сценарии запуска, Docker-проверки и конфигурация nginx
tests/, frontend/tests/, frontend/e2e/Тесты аналитики, контрактов, интерфейса и пользовательских сценариев
docs/Подробное описание данных, алгоритмов, API и развёртывания
starter/Стартовый код организаторов

Браузер получает версии CSV через /api/datasets/<dataset_id>/files/; Vite и nginx проксируют запросы к локальному API. Copilot использует соответствующий снимок и не изменяет расчёты. Новый набор заменяет CSV и снимок только после успешной проверки; ответ другой версии не показывается на новом графе.

API сохраняет загруженные версии в .money-graph/ при обычном запуске или в Docker volume datasets. При первом запуске без сохранённой версии он может импортировать готовый out/; последующий CLI-пересчёт не заменяет активную браузерную версию. Для её обновления загрузите файлы через форму. При недоступности API уже открытый граф, фильтры и карточки остаются доступны; новая загрузка и скачивание браузерных CSV требуют работающего API. Статический out/ можно просматривать отдельно.

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

1. Подготовьте окружение и данные

Для локального запуска нужны Python 3.11+, Node.js 20.19+ или 22.12+ и npm. Для контейнерного варианта нужен Docker с Compose; Python и Node.js на хосте тогда не требуются. При первоначальной установке зависимостей или сборке образов нужен доступ к сети.

Откройте терминал в корне клонированного или распакованного проекта. Датасет организаторов распространяется отдельно: data/, out/ и .money-graph/ исключены из Git и Docker build context. Для загрузки через браузер распакуйте архив в любую папку — заранее создавать data/ и рассчитывать out/ не нужно. Для CLI и скриптов run-all разместите файлы так:

data/
├── nodes.parquet
├── edges.parquet
└── transactions.parquet

2. Запустите приложение и загрузите файлы

Одна команда из корня репозитория для Docker Desktop / Docker Engine с Compose:

docker compose up --build

Откройте http://127.0.0.1:8501, выберите три файла и нажмите «Построить граф». UI и API стартуют без data/ и готового out/; отдельный batch-пайплайн не запускается. После расчёта доступны граф, карточки, топ-лист, скачивание трёх CSV и локальный Copilot без NVIDIA-ключа. «Загрузить другой набор» запускает новый анализ; ошибка не заменяет предыдущие результаты.

Лимит — 10 МиБ на файл, 32 МиБ на запрос. Состояния загрузки, проверки и расчёта показываются отдельно; одновременно выполняется один расчёт. Неверный файл, повреждённый Parquet, ошибка схемы или превышение лимита дают сообщение для исправления ввода. ZIP нужно распаковать до выбора файлов. Формат входа, ошибки и API.

Для фонового запуска добавьте -d. Остановка: docker compose down. Загруженные файлы, CSV и активная версия сохраняются в именованном volume datasets; обычный down и пересборка его сохраняют. Не добавляйте -v, если хотите сохранить анализ. Старые версии автоматически не удаляются. API не публикуется отдельным портом: nginx передаёт /api/* внутри Docker. Запуск и хранение.

Локальный запуск из готового data/ без Docker

Windows, PowerShell или CMD:

.\scripts\run-all.cmd -CheckRepro

macOS / Linux:

bash scripts/run-all.sh --check-repro

Скрипты создают .venv при необходимости, устанавливают недостающие зависимости, рассчитывают out/, запускают Copilot API и открывают интерфейс. Флаг проверки воспроизводимости запускает расчёт дважды и сравнивает SHA-256 четырёх CSV; без флага выполняется один расчёт.

Скрипты используют уже подготовленный data/; после запуска новый набор можно загрузить через форму без перезапуска. Для просмотра статического out/ без API предусмотрены -NoCopilot в Windows и --no-copilot в Bash; загрузка файлов в этом режиме недоступна. Vite проксирует API на порт 8765, поэтому для обычного демо используйте этот порт.

Ручной запуск отдельных компонентов

В первом терминале из корня проекта создайте окружение, установите зависимости, выполните расчёт и запустите API. На macOS системный python3 может быть 3.9: явно выберите установленный Python 3.11 или новее. Для браузерной загрузки строку -m money_graph можно пропустить.

Windows / PowerShell:

py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m money_graph --data data --out out --check-repro
.\.venv\Scripts\python.exe -m agent_orchestrator.server --out out

macOS / Linux:

python3.11 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m money_graph --data data --out out --check-repro
.venv/bin/python -m agent_orchestrator.server --out out

Во втором терминале из корня проекта:

cd frontend
npm ci
npm run dev -- --host 127.0.0.1 --port 5173 --open

Для расчёта только CSV достаточно команды -m money_graph; API и интерфейс не нужны. Команда npm run build в frontend/ собирает интерфейс и включает имеющиеся на момент сборки out/*.csv в dist/out/.

Отдельный CLI/batch через Docker

Для воспроизводимости жюри распакуйте три файла в data/. На macOS/Linux из корня проекта:

bash scripts/docker-compose.sh run --build --rm pipeline

Обёртка создаёт out/ и передаёт UID/GID текущего пользователя только batch-пайплайну для записи результатов на хосте. Copilot работает от UID 10001 и пишет в свой named volume. При прямом вызове Compose подготовьте права out/ по инструкции.

На Windows / PowerShell с Docker Desktop:

New-Item -ItemType Directory -Force out | Out-Null
docker compose run --build --rm pipeline

Batch читает data/ только для чтения, создаёт четыре CSV и отчёты в out/, выполняет --check-repro. Профиль batch не нужен для обычного запуска браузерного приложения. Этот отдельный прогон не заменяет уже активный загруженный набор. Настройка портов, каталогов и дополнительные проверки описаны в docs/deployment.md.

Просмотр интерфейса без датасета

Запустите только frontend командами npm ci и npm run dev из frontend/. Если out/ отсутствует, на экране ошибки нажмите «Открыть демо-набор». Загрузятся небольшие синтетические CSV из frontend/public/fixtures/.

Этот режим позволяет посмотреть граф и интерфейс. Запросы Copilot в нём отключены; для полной проверки нужен датасет и результаты пайплайна.

Опциональное подключение NVIDIA

Локальный Copilot работает без настройки провайдера. Для внешнего AI задайте NVIDIA_API_KEY и NVIDIA_MODEL в окружении процесса API. При запуске Docker Compose можно скопировать .env.example в .env и заполнить оба значения локально. Обычный Python-запуск сам .env не читает.

После запуска настроенного API включите «Использовать AI» для нужного вопроса. В CLI этому соответствует флаг --nvidia. Наличие ключа само по себе не инициирует обращение к провайдеру. При ошибке, тайм-ауте или исчерпании квоты предусмотрен переход на проверенный локальный ответ.

Ключ хранится на серверной стороне. Состав передаваемых данных и роль модели описаны ниже и в docs/agent_orchestrator.md.

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

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

  1. Запустите приложение и загрузите три Parquet через UI. Дождитесь завершения анализа и проверьте ссылки на три CSV. Для отдельной проверки воспроизводимости выполните CLI с --check-repro: в out/ появятся четыре CSV и отчёты, в run_report.json поле reproducibility.identical должно быть true.
  2. Откройте интерфейс. Для набора, описанного в репозитории, ожидаются 2 248 узлов и 3 119 направленных связей. Источник чисел — описание датасета.
  3. Выберите первого клиента в очереди проверки. Откройте карточку, изучите роль, приоритет, входящие и исходящие суммы. Найдите тот же GID в скачанных top_nodes.csv и nodes_roles.csv текущего набора: роль и приоритет должны совпасть с интерфейсом. Длинные GID сравнивайте как строки.
  4. Откройте Copilot. Нажмите подсказку «Почему этот узел в топе?», затем «Разобрать вопрос», оставив внешний AI выключенным. В ответе должны быть факты с источниками и следующий шаг. Переход по GID открывает карточку; связи, если они присутствуют в ответе, подсвечиваются на графе.
  5. Проверьте границу данных. Выберите фильтр глубины 4, откройте любой узел и панель «Каких данных не хватает?» в Copilot. Она должна указать на ненаблюдаемые исходящие переводы и предложить запрос выписки. Отсутствие видимого оттока не должно превращаться в вывод о конечном получателе.
  6. Сохраните результат. Нажмите «Добавить узел в дело» в карточке и «Сохранить ответ в дело» у ответа Copilot. Откройте значок папки слева, добавьте гипотезу и заметки, скачайте JSON и «Печатную справку». После обновления страницы локальное дело должно сохраниться.

Команды проверки

Для PR в main настроен CI: Python, frontend и локальный Copilot. Он использует отдельный синтетический Parquet; проверки на архиве организаторов остаются отдельной частью приёмки.

Следующие Python-команды выполняются из корня проекта интерпретатором .venv: замените python на .\.venv\Scripts\python.exe в Windows или .venv/bin/python в macOS/Linux.

python -m money_graph --data data --out out --check-repro
python -m agent_tools.evaluation --out out
python -m pytest tests -q

agent_tools.evaluation проверяет пять сценариев: приоритет, общий сборщик, входящие/исходящие связи, границу четвёртого колена и пустой результат. По умолчанию используется локальный эталонный ответчик; эта команда не измеряет качество внешней LLM. Тесты на реальном датасете пропускаются при отсутствии data/, при этом проверки на синтетических данных остаются доступны.

Проверки и сборка интерфейса:

cd frontend
npm test
npm run build

Браузерные тесты требуют работающих API, интерфейса и загруженного набора либо импортированного реального out/. Проверки загрузки и смены версии описаны в docs/uploads.md. Установите Chromium командой npx playwright install chromium, затем из frontend/ укажите адрес запущенного UI.

PowerShell:

$env:COPILOT_UI_URL = "http://127.0.0.1:5173"
npm run test:e2e

Bash:

COPILOT_UI_URL=http://127.0.0.1:5173 npm run test:e2e

Коды завершения CLI пайплайна: 0 — успех, 2 — ошибка входных данных, 3 — ошибка выходных таблиц, 4 — несовпадение файлов повторного расчёта. Время выполнения и результаты проверок следует брать из отчёта своего запуска.

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

Исходный набор. По docs/DATA_README.md, это обезличенный граф внутрибанковских переводов за 1–31 июля 2026 года, построенный по исходящим переводам от 81 seed-клиента до глубины четырёх колен, с порогом суммы 5 000 KZT. Seed — исходные клиенты, от которых начинался обход.

ФайлОбъём описанного набораОсновные поля
nodes.parquet2 248 узловgid, depth, is_seed
edges.parquet3 119 направленных парsrc, dst, sum_kzt, n_tx, depth
transactions.parquet4 840 транзакцийsrc, dst, date, sum_kzt

Деньги измеряются в тенге (KZT), даты операций имеют точность до дня. GID — обезличенный идентификатор; в браузере он хранится строкой для сохранения точности длинных чисел. Схема проверяется в money_graph/io.py. Синтетический набор для просмотра интерфейса хранится отдельно в frontend/public/fixtures/.

Локальный API. POST /api/datasets/jobs принимает три Parquet, GET /api/datasets/jobs/<job_id> возвращает состояние расчёта, GET /api/datasets/active — активную версию. GET /api/datasets/<dataset_id>/files/<file> отдаёт CSV этой версии. GET /api/copilot/status сообщает готовность анализа, идентификатор набора и наличие настройки NVIDIA. POST /api/copilot/answer принимает вопрос, выбранные GID, глубину обхода и флаг использования AI. Источником фактов служат готовые CSV, доступные инструментам только для чтения.

Внешний AI-сервис. В адаптере задан endpoint https://integrate.api.nvidia.com/v1/chat/completions. При явном включении AI туда передаются вопрос, выбранные GID, допустимый план вызовов и ограниченный набор структурированных фактов. Полный датасет и свободные тексты evidence/priority_why из CSV не передаются. Модель выбирает акценты и следующий шаг из разрешённого набора; итоговое текстовое резюме формируется локально, ранжирование кандидатов не зависит от модели.

Подключений к банковской системе, внешним реестрам клиентов или сервису автоматической отправки запросов в текущем коде нет.

Ограничения текущей версии

  • Неполный охват переводов. Видны операции только в пределах периода, порога суммы и исходящего обхода. У узлов depth=4 исходящие связи не выгружались; входящие от клиентов за пределами набора также не видны. Начальные остатки отсутствуют. Эти ограничения учитываются в признаках, правилах и предупреждениях.
  • Время не доказывает движение тех же денег. Нет порядка операций внутри дня и сопоставления входящих сумм с конкретными исходящими переводами. Быстрый отток и циклы — признаки для проверки гипотезы.
  • Правила не обучены на размеченных нарушениях. Пороги и веса заданы в коде; подтверждённых метрик обнаружения нарушений на размеченной выборке репозиторий не содержит. Проверка фактов Copilot подтверждает соответствие CSV и ограниченному формату ответа.
  • Copilot поддерживает ограниченный набор сценариев. Вопрос — до 1 000 символов, контекст — до пяти GID, обход — до четырёх шагов. Нераспознанный вопрос возвращает сообщение об ограничении. Внешний AI требует настроенной модели, ключа, сети и доступной квоты.
  • Локальная работа со снимком. Нет потокового обновления банковских данных. Браузер принимает три Parquet и автоматически переключает граф и Copilot после успешного анализа; CLI остаётся отдельным batch-сценарием. ZIP-импорт, очередь параллельных расчётов и автоматическое удаление старых наборов не реализованы.
  • Масштаб ограничен текущим подходом. Граф и таблицы обрабатываются в памяти через NetworkX и pandas. Распределённая обработка не реализована. Лимит базового отображения графа в UI регулируется от 30 до 500 узлов; узлы из проверенного ответа могут добавляться сверх этого вида.
  • Дело хранится в браузере. Нет серверного хранилища дел, учётных записей и совместного редактирования. Очистка локального хранилища удалит дело, если не сохранён JSON. Ограничения: 100 материалов на дело и до 4 000 000 байт для файла импорта. Подробности — в docs/case_file.md.
  • Развёртывание рассчитано на локальное демо. В текущей конфигурации нет пользовательской аутентификации и TLS. Публичная эксплуатация требует отдельной настройки доступа и инфраструктуры.
  • Воспроизводимость проверяется в одном окружении. --check-repro сравнивает два расчёта на одной машине; между версиями библиотек и платформами возможны различия. Версия NetworkX закреплена, остальные версии фиксируются в отчёте запуска.

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

Ссылка на публичную развёрнутую версию в репозитории не указана. Для демонстрации предусмотрены локальные адреса http://127.0.0.1:5173 при запуске Vite и http://127.0.0.1:8501 при запуске Docker Compose.

Подробная инструкция: docs/deployment.md.

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

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

sherhankuralov-netizen 45Bekzat Yessimkhanuly 37amanzhol-arhat 25Bekzat Yessimkhanuly 9

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

  • 2026-09-23 17:59Merge pull request #29 from BAITC-Hacks/bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:58fix: isolate upload CI state and make resilience batch-only (PAN-58)Bekzat Yessimkhanuly
  • 2026-09-23 17:57Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:57test(PAN-58): support unified navigation in upload testsBekzat Yessimkhanuly
  • 2026-09-23 17:57Merge pull request #33 from BAITC-Hacks/bekzat/pan-61-complete-displayBekzat Yessimkhanuly
  • 2026-09-23 17:55Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:54Merge remote-tracking branch 'origin/main' into bekzat/pan-61-complete-displayBekzat Yessimkhanuly
  • 2026-09-23 17:52Merge pull request #32 from BAITC-Hacks/bekzat/pan-59-gid-navigationBekzat Yessimkhanuly
Все коммиты (113)
  • 2026-09-23 17:51Merge pull request #30 from BAITC-Hacks/sherhankuralov/pan-69-priemkaci-avtomaticheskie-proverki-pr-python-frontend-isherhankuralov-netizen
  • 2026-09-23 17:51Merge pull request #28 from BAITC-Hacks/aarhat144/pan-55-uluchshenie-interaktivnoe-izyatie-top-n-i-sravneniesherhankuralov-netizen
  • 2026-09-23 17:51Merge remote-tracking branch 'origin/main' into aarhat144/pan-55-uluchshenie-interaktivnoe-izyatie-top-n-i-sravnenieamanzhol-arhat
  • 2026-09-23 17:51Merge origin/main into PAN-55: сохранить casebook и раздел устойчивостиamanzhol-arhat
  • 2026-09-23 17:51Merge pull request #31 from BAITC-Hacks/sherhankuralov/pan-68-submission-kitsherhankuralov-netizen
  • 2026-09-23 17:50Merge remote-tracking branch 'origin/main' into bekzat/pan-59-gid-navigationBekzat Yessimkhanuly
  • 2026-09-23 17:50PAN-69: add PR CI for Python, frontend and local Copilotsherhankuralov-netizen
  • 2026-09-23 17:49Merge remote-tracking branch 'origin/main' into bekzat/pan-59-gid-navigationBekzat Yessimkhanuly
  • 2026-09-23 17:49Refactor README.md for clarity and structure; update project description, installation instructions, and usage details for AML analytics pipeline.amanzhol-arhat
  • 2026-09-23 17:48feat: show visible cluster legend and complete list counts (PAN-61)Bekzat Yessimkhanuly
  • 2026-09-23 17:46PAN-68: enable frontend validation of the exact submission CSVssherhankuralov-netizen
  • 2026-09-23 17:44PAN-68: build commit-bound acceptance packet and defense casessherhankuralov-netizen
  • 2026-09-23 17:44PAN-68: record pending checks and execution environment explicitlysherhankuralov-netizen
  • 2026-09-23 17:43PAN-55: интерактивное изъятие top-N и сравнение устойчивости сетиamanzhol-arhat
  • 2026-09-23 17:42Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:40fix: preserve neighborhood bounds after canvas resizeBekzat Yessimkhanuly
  • 2026-09-23 17:36Merge branch 'main' of https://github.com/BAITC-Hacks/hack-a7ea453a-taymas-solutionsamanzhol-arhat
  • 2026-09-23 17:36feat: enhance local demo setup by automatically opening Vite UI in the browseramanzhol-arhat
  • 2026-09-23 17:35Merge pull request #26 from BAITC-Hacks/bekzat/pan-64-csv-validationBekzat Yessimkhanuly
  • 2026-09-23 17:35Merge pull request #27 from BAITC-Hacks/sherhankuralov/pan-52-uluchshenie-delo-rassledovaniya-sokhranenie-faktov-zametki-isherhankuralov-netizen
  • 2026-09-23 17:33Merge branch 'main' of https://github.com/BAITC-Hacks/hack-a7ea453a-taymas-solutionsamanzhol-arhat
  • 2026-09-23 17:32feat: update README and scripts for improved local demo setupamanzhol-arhat
  • 2026-09-23 17:30PAN-52: add local investigation casebook with versioned evidence and exportssherhankuralov-netizen
  • 2026-09-23 17:29Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:29Merge pull request #25 from BAITC-Hacks/sherhankuralov/pan-66-docker-smokesherhankuralov-netizen
  • 2026-09-23 17:29Merge remote-tracking branch 'origin/main' into bekzat/pan-64-csv-validationBekzat Yessimkhanuly
  • 2026-09-23 17:28PAN-66: align Docker ownership and verify Copilot fallback and outagesherhankuralov-netizen
  • 2026-09-23 17:22fix: fit full observed neighborhood when navigating GIDsBekzat Yessimkhanuly
  • 2026-09-23 17:20Merge remote-tracking branch 'origin/main' into bekzat/pan-59-gid-navigationBekzat Yessimkhanuly
  • 2026-09-23 17:20fix: preserve complete GID navigation context (PAN-59)Bekzat Yessimkhanuly
  • 2026-09-23 17:17Merge pull request #23 from BAITC-Hacks/sherhankuralov/pan-63-fast-out-semanticssherhankuralov-netizen
  • 2026-09-23 17:17Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:16Merge remote-tracking branch 'origin/main' into bekzat/pan-64-csv-validationBekzat Yessimkhanuly
  • 2026-09-23 17:15test(PAN-58): adapt upload smoke to current workspaceBekzat Yessimkhanuly
  • 2026-09-23 17:15Merge pull request #24 from BAITC-Hacks/bekzat/pan-67-dependency-hygieneBekzat Yessimkhanuly
  • 2026-09-23 17:12PAN-63: clarify temporal proximity evidence and limitssherhankuralov-netizen
  • 2026-09-23 17:12fix(PAN-58): recognize uploaded datasets in request plansBekzat Yessimkhanuly
  • 2026-09-23 17:10fix: reject nonfinite inputs and sum overflow (PAN-65)amanzhol-arhat
  • 2026-09-23 17:10PAN-64: validate CSV values and graph references before renderingBekzat Yessimkhanuly
  • 2026-09-23 17:10Merge remote-tracking branch 'origin/main' into bekzat/pan-64-csv-validationBekzat Yessimkhanuly
  • 2026-09-23 17:10docs: record PAN-67 checks against current mainBekzat Yessimkhanuly
  • 2026-09-23 17:08Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 17:07Merge remote-tracking branch 'origin/main' into bekzat/pan-67-dependency-hygieneBekzat Yessimkhanuly
  • 2026-09-23 17:07chore: protect local secrets and update Vitest (PAN-67)Bekzat Yessimkhanuly
  • 2026-09-23 17:05Merge remote-tracking branch 'origin/main' into aarhat144/pan-62-verified-summaryamanzhol-arhat
  • 2026-09-23 17:05fix: bind verified summaries to typed claims (PAN-62)amanzhol-arhat
  • 2026-09-23 17:04fix(PAN-58): preserve exact IDs and recover interrupted uploadsBekzat Yessimkhanuly
  • 2026-09-23 17:04Merge pull request #22 from BAITC-Hacks/codex/taymas-investigation-uisherhankuralov-netizen
  • 2026-09-23 17:03Merge pull request #21 from BAITC-Hacks/sherhankuralov/pan-60-fix-mixed-cyclessherhankuralov-netizen
  • 2026-09-23 17:02feat(ui): redesign Taymas investigation workspacesherhankuralov-netizen
  • 2026-09-23 17:02feat(ui): add focus mode and preserve graph context across copilot answerssherhankuralov-netizen
  • 2026-09-23 17:02feat(ui): theme data request plans and finish copilot navigation polishsherhankuralov-netizen
  • 2026-09-23 17:00PAN-60: detect long cycles independently of shorter return pathssherhankuralov-netizen
  • 2026-09-23 17:00Merge remote-tracking branch 'origin/main' into sherhankuralov/pan-60-fix-mixed-cyclessherhankuralov-netizen
  • 2026-09-23 16:59feat(PAN-58): upload Parquet and publish versioned graph snapshotsBekzat Yessimkhanuly
  • 2026-09-23 16:59Merge remote-tracking branch 'origin/main' into bekzat/pan-58-parquet-uploadBekzat Yessimkhanuly
  • 2026-09-23 16:59Merge pull request #20 from BAITC-Hacks/sherhankuralov/pan-57-uluchshenie-sravnenie-kandidatov-i-ustoichivost-ikhsherhankuralov-netizen
  • 2026-09-23 16:55PAN-57: compare candidate priorities and pair stabilitysherhankuralov-netizen
  • 2026-09-23 16:47Merge pull request #19 from BAITC-Hacks/sherhankuralov/pan-54-data-request-plansherhankuralov-netizen
  • 2026-09-23 16:44PAN-54: add local data request plans with source-backed hypothesessherhankuralov-netizen
  • 2026-09-23 16:16Merge pull request #18 from BAITC-Hacks/sherhankuralov/pan-48-react-ai-assistant-panel-i-case-briefsherhankuralov-netizen
  • 2026-09-23 16:13PAN-48: integrate Docker bridge, polish panel and document demosherhankuralov-netizen
  • 2026-09-23 16:02Merge main: preserve PAN-39 node details and PAN-41 deploymentsherhankuralov-netizen
  • 2026-09-23 16:01PAN-48: add investigation panel, verified brief and local APIsherhankuralov-netizen
  • 2026-09-23 15:54feat: add reproducible Docker deployment (PAN-41)Bekzat Yessimkhanuly
  • 2026-09-23 15:46feat: enhance React node details and neighbor flows (PAN-39)Bekzat Yessimkhanuly
  • 2026-09-23 15:44feat: add reproducible Docker deploymentBekzat Yessimkhanuly
  • 2026-09-23 15:42docs: document React demo and architecture (PAN-40) (#15)Bekzat Yessimkhanuly
  • 2026-09-23 15:42Merge pull request #14 from BAITC-Hacks/sherhankuralov/pan-46-agent-orchestrator-i-optional-nvidia-api-adaptersherhankuralov-netizen
  • 2026-09-23 15:42docs: require supported Python runtimeBekzat Yessimkhanuly
  • 2026-09-23 15:41feat: add AML node investigation detailsBekzat Yessimkhanuly
  • 2026-09-23 15:38docs: document React demo and architecture (PAN-40)Bekzat Yessimkhanuly
  • 2026-09-23 15:38PAN-46: add bounded AML copilot and optional NVIDIA adaptersherhankuralov-netizen
  • 2026-09-23 15:35feat: add React Cytoscape network viewer (PAN-38) (#13)Bekzat Yessimkhanuly
  • 2026-09-23 15:20Merge pull request #12 from BAITC-Hacks/aarhat144/pan-47-evidence-verifier-i-evaluation-nabor-aml-voprosovArhat
  • 2026-09-23 15:20Merge pull request #10 from BAITC-Hacks/aarhat144/pan-45-agent-graph-tools-i-strukturirovannii-query-layerArhat
  • 2026-09-23 15:18PAN-47: evidence verifier и evaluation-набор AML-вопросовamanzhol-arhat
  • 2026-09-23 15:17Merge pull request #11 from BAITC-Hacks/sherhankuralov/pan-50-sohlasovat-poroh-vkhod-nepolnii-mezhdu-rolyami-isherhankuralov-netizen
  • 2026-09-23 15:16PAN-50: один порог «вход неполный» для ролей и priority_scoresherhankuralov-netizen
  • 2026-09-23 15:10PAN-45: read-only инструменты графа для AML-агентаamanzhol-arhat
  • 2026-09-23 15:00feat: updt reviewamanzhol-arhat
  • 2026-09-23 14:54Merge pull request #9 from BAITC-Hacks/aarhat144/fix-roles-external-inflowArhat
  • 2026-09-23 14:51Merge remote-tracking branch 'origin/main' into aarhat144/fix-roles-external-inflowamanzhol-arhat
  • 2026-09-23 14:51fix: address graph viewer review feedbackBekzat Yessimkhanuly
  • 2026-09-23 14:50Merge pull request #8 from BAITC-Hacks/sherhankuralov/pan-44-bonus-ocenka-ustoichivosti-seti-pri-izyatii-top-n-uzlovsherhankuralov-netizen
  • 2026-09-23 14:50Merge pull request #7 from BAITC-Hacks/sherhankuralov/pan-43-podklyuchit-analyticspriority-i-analyticstop_nodes-vsherhankuralov-netizen
  • 2026-09-23 14:50Роли на границе выгрузки: внешний источник денег, seed, скорость транзитаamanzhol-arhat
  • 2026-09-23 14:33PAN-44: evaluate network resilience under ranked node removalsherhankuralov-netizen
  • 2026-09-23 14:30PAN-43: priority_score и top_nodes.csv в пайплайне из analyticssherhankuralov-netizen
  • 2026-09-23 14:21Merge pull request #6 from BAITC-Hacks/aarhat144/pan-34-sobrat-nodes_rolescsv-i-smoke-proverki-vosproizvodimostiArhat
  • 2026-09-23 14:15PAN-34: контракт nodes_roles.csv, smoke-проверки, отчёт о прогонеamanzhol-arhat
  • 2026-09-23 14:15Merge pull request #2 from BAITC-Hacks/sherhankuralov/pan-37-sformirovat-top_nodescsv-i-analiticheskie-proverkisherhankuralov-netizen
  • 2026-09-23 14:14Merge pull request #3 from BAITC-Hacks/sherhankuralov/pan-36-rasschitat-priority_score-po-obyasnimoi-formulesherhankuralov-netizen
  • 2026-09-23 14:12PAN-36: транзит только при полном входе, why без сокращенийsherhankuralov-netizen
  • 2026-09-23 14:12feat: add local transaction graph viewerBekzat Yessimkhanuly
  • 2026-09-23 14:10PAN-37: validate numeric evidence and decouple optional role fieldssherhankuralov-netizen
  • 2026-09-23 14:08Merge pull request #4 from BAITC-Hacks/aarhat144/pan-32-sobrat-zahruzchik-parquet-validaciyu-skhem-i-feature-tableArhat
  • 2026-09-23 14:06PAN-32: контракт входных данных, таблица рёбер, boundary_depth4amanzhol-arhat
  • 2026-09-23 14:04PAN-36: priority_score по объяснимой формулеsherhankuralov-netizen
  • 2026-09-23 14:00Признаки и роли узлов: пакет money_graphamanzhol-arhat
  • 2026-09-23 14:00PAN-37: build deterministic top nodes and audit analytical outputssherhankuralov-netizen
  • 2026-09-23 13:48chore: add hackalem starter and first-run docsBekzat Yessimkhanuly
  • 2026-09-23 13:46Merge pull request #1 from BAITC-Hacks/sherhankuralov/pan-35-realizovat-klasterizaciyu-i-svodku-clusterscsvsherhankuralov-netizen
  • 2026-09-23 13:45PAN-35: data/ вне git, networkx 3.6.1, проверка на Python 3.11sherhankuralov-netizen
  • 2026-09-23 13:34PAN-35: кластеризация графа и clusters.csvsherhankuralov-netizen
Структура репозитория (187 файлов)
.dockerignore
.env.example
.github/workflows/ci.yml
.gitignore
Dockerfile
README.md
agent_orchestrator/__init__.py
agent_orchestrator/__main__.py
agent_orchestrator/brief.py
agent_orchestrator/contracts.py
agent_orchestrator/datasets.py
agent_orchestrator/nvidia.py
agent_orchestrator/orchestrator.py
agent_orchestrator/router.py
agent_orchestrator/schemas.py
agent_orchestrator/server.py
agent_tools/__init__.py
agent_tools/__main__.py
agent_tools/answer.py
agent_tools/errors.py
agent_tools/evaluation.py
agent_tools/safety.py
agent_tools/schemas.py
agent_tools/store.py
agent_tools/tools.py
agent_tools/verifier.py
analytics/__init__.py
analytics/clustering.py
analytics/priority.py
analytics/priority_compare.py
analytics/resilience.py
analytics/resilience_export.py
analytics/top_nodes.py
deploy/nginx.conf
docker-compose.yml
docs/DATA_README.md
docs/agent_orchestrator.md
docs/agent_tools.md
docs/agent_verifier.md
docs/audit-2026-09-23.md
docs/case_file.md
docs/ci.md
docs/clustering.md
docs/copilot_panel.md
docs/csv-validation.md
docs/data_request_plan.md
docs/deployment.md
docs/features.md
docs/priority.md
docs/priority_compare.md
docs/resilience.md
docs/security-verification.md
docs/submission_kit.md
docs/top_nodes.md
docs/uploads.md
frontend/.gitignore
frontend/README.md
frontend/e2e/casebook.spec.ts
frontend/e2e/complete-display.spec.ts
frontend/e2e/copilot.spec.ts
frontend/e2e/data-request.spec.ts
frontend/e2e/navigation.spec.ts
frontend/e2e/resilience.spec.ts
frontend/e2e/upload.spec.ts
frontend/index.html
frontend/package-lock.json
frontend/package.json
frontend/playwright.config.ts
frontend/public/fixtures/clusters.csv
frontend/public/fixtures/edge_table.csv
frontend/public/fixtures/nodes_roles.csv
frontend/public/fixtures/resilience.json
frontend/public/fixtures/top_nodes.csv
frontend/src/App.tsx
frontend/src/DatasetUpload.tsx
frontend/src/GraphCanvas.tsx
frontend/src/casebook/CaseWorkspace.tsx
frontend/src/casebook/casebook.css
frontend/src/casebook/model.ts
frontend/src/casebook/report.ts
frontend/src/casebook/useCaseFile.ts
frontend/src/components/CopilotSlot.tsx
frontend/src/components/FilterPanel.tsx
frontend/src/components/GraphPanel.tsx
frontend/src/components/Header.tsx
frontend/src/components/Icon.tsx
frontend/src/components/NodeInspector.tsx
frontend/src/components/PriorityTable.tsx
frontend/src/components/States.tsx
frontend/src/copilot/CopilotPanel.tsx
frontend/src/copilot/api.ts
frontend/src/copilot/copilot.css
frontend/src/copilot/graph.ts
frontend/src/csv.ts
frontend/src/data.ts
frontend/src/datasets.ts
frontend/src/filters.ts
frontend/src/graphLayout.ts
frontend/src/investigation/DataRequestPanel.tsx
frontend/src/investigation/dataRequestPlan.css
frontend/src/investigation/dataRequestPlan.ts
frontend/src/main.tsx
frontend/src/presentation.ts
frontend/src/resilience/ResilienceGraph.tsx
frontend/src/resilience/ResiliencePanel.tsx
frontend/src/resilience/resilience.css
frontend/src/resilience/resilience.ts
frontend/src/styles.css
frontend/src/styles/copilot-integration.css
frontend/src/styles/inspector.css
frontend/src/styles/layout.css
frontend/src/styles/network.css
frontend/src/styles/tokens.css
frontend/src/styles/uploads.css
frontend/src/types.ts
frontend/tests/app.test.tsx
frontend/tests/casebook-panel.test.tsx
frontend/tests/casebook.test.ts
frontend/tests/complete-display.test.tsx
frontend/tests/copilot-fixture.ts
frontend/tests/copilot.test.tsx
frontend/tests/csv-validation.test.ts
frontend/tests/data-request-panel.test.tsx
frontend/tests/data-request-plan.test.ts
frontend/tests/data-request-real.test.ts
frontend/tests/data.test.ts
frontend/tests/graphLayout.test.ts
frontend/tests/investigation.test.ts
frontend/tests/resilience-panel.test.tsx
frontend/tests/resilience.test.ts
frontend/tests/upload.test.tsx
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
frontend/vitest.config.ts
money_graph/__init__.py
money_graph/__main__.py
money_graph/cli.py
money_graph/config.py
money_graph/features.py
money_graph/graph.py
money_graph/io.py
money_graph/outputs.py
money_graph/pipeline.py
money_graph/ranking.py
money_graph/report.py
money_graph/roles.py
requirements.txt
scripts/ci-browser.sh
scripts/ci-vite.config.ts
scripts/ci_fixture.py
scripts/docker-browser-smoke.mjs
scripts/docker-compose.sh
scripts/docker-smoke.sh
scripts/prepare_submission.py
scripts/run-all.cmd
scripts/run-all.ps1
scripts/run-all.sh
scripts/upload-smoke.py
starter/README.md
starter/requirements.txt
starter/starter.py
tests/_mini.py
tests/test_agent_eval.py
tests/test_agent_tools.py
tests/test_ci_fixture.py
tests/test_clustering.py
tests/test_copilot_server.py
tests/test_datasets.py
tests/test_evidence_verifier.py
tests/test_finite_inputs.py
tests/test_inputs.py
tests/test_orchestrator.py
tests/test_orchestrator_integration.py
tests/test_pipeline.py
tests/test_priority.py
tests/test_priority_compare.py
tests/test_ranking.py
tests/test_resilience.py
tests/test_resilience_export.py
tests/test_role_cycles.py
tests/test_roles.py
tests/test_submission_kit.py
tests/test_temporal_semantics.py
tests/test_top_nodes.py
tests/test_verified_summary.py
Ветки (35)
aarhat144/fix-roles-external-inflowaarhat144/pan-32-sobrat-zahruzchik-parquet-validaciyu-skhem-i-feature-tableaarhat144/pan-34-sobrat-nodes_rolescsv-i-smoke-proverki-vosproizvodimostiaarhat144/pan-45-agent-graph-tools-i-strukturirovannii-query-layeraarhat144/pan-47-evidence-verifier-i-evaluation-nabor-aml-voprosovaarhat144/pan-55-uluchshenie-interaktivnoe-izyatie-top-n-i-sravnenieaarhat144/pan-62-verified-summaryaarhat144/pan-65-finite-inputsbekzat/pan-38-network-viewbekzat/pan-39-react-detailbekzat/pan-40-docsbekzat/pan-41-dockerbekzat/pan-58-parquet-uploadbekzat/pan-59-gid-navigationbekzat/pan-61-complete-displaybekzat/pan-64-csv-validationbekzat/pan-67-dependency-hygienecodex/taymas-investigation-uimainsherhankuralov/pan-35-realizovat-klasterizaciyu-i-svodku-clusterscsvsherhankuralov/pan-36-rasschitat-priority_score-po-obyasnimoi-formulesherhankuralov/pan-37-sformirovat-top_nodescsv-i-analiticheskie-proverkisherhankuralov/pan-43-podklyuchit-analyticspriority-i-analyticstop_nodes-vsherhankuralov/pan-44-bonus-ocenka-ustoichivosti-seti-pri-izyatii-top-n-uzlovsherhankuralov/pan-46-agent-orchestrator-i-optional-nvidia-api-adaptersherhankuralov/pan-48-react-ai-assistant-panel-i-case-briefsherhankuralov/pan-50-sohlasovat-poroh-vkhod-nepolnii-mezhdu-rolyami-isherhankuralov/pan-52-uluchshenie-delo-rassledovaniya-sokhranenie-faktov-zametki-isherhankuralov/pan-54-data-request-plansherhankuralov/pan-57-uluchshenie-sravnenie-kandidatov-i-ustoichivost-ikhsherhankuralov/pan-60-fix-mixed-cyclessherhankuralov/pan-63-fast-out-semanticssherhankuralov/pan-66-docker-smokesherhankuralov/pan-68-submission-kitsherhankuralov/pan-69-priemkaci-avtomaticheskie-proverki-pr-python-frontend-i

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

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

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