Skip to content

renosaza/openrisk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

credit-risk-mvp

Информационная система оценки и оптимизации кредитного риска с применением ИИ и спецификации OpenAPI.

Концепция продукта (пересмотр)

Изначальная задумка — не отдельный сайт, а компактная панель, которую можно закрепить рядом с бизнес‑системой или встроить как расширение браузера. Поэтому интерфейс ориентирован на узкие экраны и работу «в две колонки»:

  • Режим расширения: UI открывается в сайдбаре браузера/плагина, тянет данные из backend и отображает ключевые KPI, скоринг, оптимизацию и очередь задач без перехода на отдельный сайт.
  • Встраивание в контекст: тот же UI может быть iframe-панелью в CRM/ERP, чтобы скоринг и мониторинг происходили прямо в рабочем окне оператора.
  • Мобильный режим: на узких экранах навигация превращается в выезжающее меню, карточки и таблицы переходят в одну колонку.

Это объясняет компактные виджеты, быстрые формы и отсутствие «толстых» страниц — всё рассчитано на быстрый взгляд.

Запуск

docker compose up --build

Если после сборки backend падает с ошибкой ImportError: no pq wrapper available, убедитесь что используется psycopg[binary] (уже добавлено в backend/requirements.txt) и пересоберите контейнер.

Если frontend сообщает: "next start" does not work with "output: standalone", запуск уже исправлен — контейнер стартует через node .next/standalone/server.js.

Переменные окружения

Переменная Описание Значение по умолчанию
DATABASE_URL строка подключения к Postgres postgresql+psycopg://postgres:postgres@db:5432/credit_risk
API_KEY ключ для заголовка X-API-Key local-dev-key
MODEL_PATH путь для модели ML /data/model.joblib
DATASET_PATH путь для синтетического датасета /data/dataset.csv
NEXT_PUBLIC_API_BASE базовый URL backend http://localhost:8000
NEXT_PUBLIC_API_KEY ключ для frontend запросов local-dev-key

UI

  • Дашборд: метрики, графики и последние задачи.
  • Скоринг заявки: форма кредитной заявки, PD/EL и факторы риска.
  • Оптимизация портфеля: запуск задачи отбора заявок при бюджетном лимите.
  • Задачи: список задач и статусов, журнал событий доступен через SSE.

Где взять API-ключ

  • По умолчанию ключ: local-dev-key (см. API_KEY в docker-compose.yml).
  • Можно заменить ключ, задав API_KEY в окружении backend и NEXT_PUBLIC_API_KEY для frontend.
  • В интерфейсе ключ вводится в сайдбаре и сохраняется локально в браузере.

API

  • Backend: http://localhost:8000
  • Docs: http://localhost:8000/docs
  • OpenAPI: http://localhost:8000/openapi.json

Как всё работает под капотом (метрики, графики, модель и потоки данных)

1. Потоки данных (end‑to‑end)

  1. UI → API: frontend обращается к backend через frontend/lib/api-client.ts и передаёт X-API-Key.
  2. API → ML/DB:
    • /api/v1/score валидирует вход, считает PD, пишет заявку и решение в БД.
    • /api/v1/jobs создаёт задачу и запускает асинхронный обработчик.
  3. DB → дашборд: /api/v1/dashboard собирает данные по заявкам, решениям и задачам.

2. ML‑скоринг

  • Где живёт: backend/app/ml/model.py.
  • Что делает: обучает/грузит модель, возвращает pd и top_factors.
  • Как используется: backend/app/api/v1/routes.py вызывает score_application, вычисляет ожидаемые потери (EL) по формуле EL = PD * LGD * EAD, где:
    • PD — вероятность дефолта (модель).
    • LGD — допущение 0.5 (константа в коде).
    • EAD — сумма кредита в рублях.

Все денежные входы и результаты интерпретируются как российские рубли (RUB).

3. Таблицы БД и сущности

  • Application: входные параметры клиента.
  • Decision: результат скоринга (PD, EL, рекомендация).
  • Job и JobEvent: очередь задач, прогресс и журнал событий.

4. Дашборд: каждая метрика и каждый график

Источник — backend/app/api/v1/routes.py (эндпоинт /api/v1/dashboard).

Метрики (карточки вверху)

  1. Всего заявок (total_applications)
    • Число активных заявок, пригодных для портфеля.
    • Отказанные и удалённые скоринги сюда не входят.
  2. Доля одобрений (approved_rate)
    • Доля решений, где Decision.recommended == True.
    • Показывает качество входящего потока и агрессивность скоринга.
  3. Средняя PD (average_pd)
    • Среднее значение PD по всем решениям.
    • Чем выше, тем рисковее портфель.
  4. Ожидаемые потери портфеля (portfolio_el)
    • Сумма Decision.expected_loss по активным портфельным решениям.
    • Это агрегированный риск в рублях.
  5. Отказано (rejected_count)
    • Количество неудалённых заявок с высоким риском и рекомендацией «Отказать».

График 1: «Распределение PD»

  • Откуда берётся: список Decision.pd.
  • Что показывает: плотность риска по портфелю (сколько заявок попадает в низкий/средний/высокий PD).
  • Почему важно: позволяет визуально отделить «здоровую» часть портфеля от высокорисковой.

График 2: «EL во времени»

  • Откуда берётся: история Decision.expected_loss.
  • Что показывает: изменение ожидаемых потерь по последовательным решениям (как меняется риск на потоке).
  • Почему важно: видны сдвиги качества выдачи и всплески риска.

Дополнительные данные дашборда

  • Последние задачи (recent_jobs) — отображаются на странице задач.
  • Прогресс задач (job_durations) — сервисные метрики для мониторинга очереди.

Реалистичное поведение метрик

Если в БД ещё нет активных портфельных заявок, backend возвращает пустые метрики и empty state на UI. Локальная frontend-симуляция включается только если API недоступен, и тогда интерфейс явно показывает предупреждение.

На frontend при отсутствии ответа API включается аналогичная симуляция frontend/lib/dashboard-simulator.ts.

5. Страница скоринга (Score)

  • PD: результат модели (ScoreResponse.pd).
  • Ожидаемые потери: pd * lgd * ead, где lgd = 0.5, а ead = loan_amount.
  • Рекомендация:
    • PD < 10%: «Одобрить».
    • 10% <= PD < 20%: «На ручную проверку».
    • PD >= 20%: «Отказать».
  • Топ‑факторы: ScoreResponse.top_factors — объяснение ключевых признаков.
  • История скорингов: /api/v1/scores/history возвращает последние неудалённые скоринги. Записи можно удалить soft delete через DELETE /api/v1/scores/{id} или очистить через DELETE /api/v1/scores.

6. Страница оптимизации портфеля

  • Вход: список заявок + бюджет в рублях.
  • Механика:
    • Каждую заявку скорим через ML.
    • Считаем expected_loss = pd * lgd * ead.
    • Считаем процентный доход и expected_profit = gross_interest_income - expected_loss.
    • Исключаем высокий риск, отказы и заявки с неположительной ожидаемой прибылью.
    • Greedy-эвристика отбирает заявки по expected_profit / loan_amount при ограничении лимита выдачи.
  • Где реализовано: backend/app/jobs/runner.py (_run_optimize).

7. Очередь задач

  • Задача — асинхронная операция (оптимизация или переобучение модели).
  • SSE‑лог: /api/v1/jobs/{id}/events стримит события, события пишутся в JobEvent.
  • Зачем: позволяет пользователю видеть ход долгих операций в реальном времени.

8. Темы и адаптивность

  • Темы: CSS‑переменные в frontend/app/globals.css задают корректные цветовые значения для светлой и тёмной темы, включая графики и градиенты.
  • Адаптивность: frontend/components/app-shell.tsx превращает меню в выезжающую панель на мобильных экранах.

Что делать дальше

  1. Соберите и запустите все сервисы:
    docker compose up --build
  2. Откройте UI:
    • http://localhost:3000
  3. Проверьте backend:
    • http://localhost:8000/health
    • http://localhost:8000/docs
  4. Запустите оптимизацию портфеля:
    • UI → Оптимизация портфеляЗапустить оптимизацию
  5. Откройте журнал событий задачи:
    • UI → Задачи → выберите задачу → наблюдайте SSE лог.

Пример запроса

curl -X POST http://localhost:8000/api/v1/score \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-dev-key" \
  -d '{
    "age": 35,
    "income": 120000,
    "employment_years": 6,
    "debt_to_income": 0.32,
    "credit_history_months": 84,
    "delinquencies": 0,
    "loan_amount": 800000,
    "loan_term_months": 36,
    "interest_rate": 18.5
  }'

OpenAPI снапшоты

make export-openapi

Снапшоты лежат в openapi/openapi.json и openapi/openapi.yaml.

Как это закрывает лабораторную по синхронизации

SYNC-LAB точки:

  • backend/app/core/sync.py: scoring_semaphore ограничивает параллельные скоринги.
  • backend/app/core/sync.py: model_lock защищает модель во время retrain.
  • backend/app/core/sync.py: job_channels (Condition) уведомляет SSE подписчиков.
  • backend/app/jobs/runner.py: использование Semaphore/Lock при запуске задач.

Тесты

cd backend
pytest

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors