"РЕКЛАМУШКА" представляет собой технологичное B2B и B2C решение. Бизнес может запустить свою рекламную кампанию и получить максимальные охваты, а пользователи увидеть релевантную для них рекламу.
Разработано API, а также доступен интерфейс в виде Telegram-бота и дашборды в Grafana.
- Стек технологий и внешние зависимости
- Инстукция по запуску
- Демонстрация работы приложения
- Схема базы данных
- Описание работы основных точек входа
- Тестирование
В этом разделе представлены используемые технологии и зависимости с обоснованием их выбора.
В целом, данные инструменты были выбраны из-за их популярности, удобства разработки и перспективы масштабирования.
- Скопируйте данный репозиторий
git clone [email protected]:2025-final-projects-back/Tanax-Xt.git
-
При необходимости отредактируйте секреты приложения. Про них чуть ниже
-
Запустите проект через docker-compose. Про его устройство ниже
docker compose up -d
После этого дождитесь запуска контейнеров (при первом запуске время билда 3-5 минут в зависимости от интернет-соединения).
- Документация API будет доступна по адресу http://localhost:8080/docs
- Чтобы использовать
Grafana
, перейдите http://localhost:3000 логин/пароль - admin/adminВ первое время не для всех графиков могут собраться данные, в таком случае необходимо просто обновить сайт через некоторое время
- Бот будет запущен здесь http://t.me/marketing_management_system_bot
- Остановить проект можно командой
docker compose down
Секреты приложения намеренно вынесены в docker-compose, согласно требованиям.
При необходимости, замените следующие поля на свои (если вы будете менять секреты, связанные с БД или МИНИО, продублируйте свои действия в файле src/config.py):
YANDEX_GPT_API_KEY=SECRET
FOLDER_ID=SECRET
POSTGRES_DB=prod3
POSTGRES_USER=postgres
POSTGRES_PASSWORD=root
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=admin
TELEGRAM_ID=SECRET
TELEGRAM_ALERT_BOT_TOKEN=SECRET
TELEGRAM_BOT_TOKEN=SECRET
MINIO_ROOT_USER=root
MINIO_ROOT_PASSWORD=password
backend
- основное приложение, реализующее API. Стартует только после:- Запуска Redis
- Запуска базы данных для продакшена
- Запуска тестов
db
- продакшен база данныхredis
- бд для хэшированияtest
- e2e-тесты. Стартует только после:- Запуска Redis
- Запуска базы данных для тестов
db-test
- база данных для тестированияprometheus
- сервис для сбора статистикиgrafana
- сервис для визуализации статистики. Зависит от:- Запуска prometheus
alertmanager
- сервис для оповещения об инцидентахbot
- поднимает тг-бота для взаимодействия с бэкендом. Бот будет доступен в @marketing_management_system_bot. Зависит от:- Запуска бэкенда
s3-storage
- сервис для хранения данных в S3
В docker-compose
в сервисе alertmanager
замените TELEGRAM_ID
на свой, если хотите получать уведомления в
Телеграме.
Для того, чтобы узнать свой id можно воспользоваться сторонним сервисом, например, данным ботом.
❗ Ссылка ведет на сторонний ресурс, не имеющий отнощения к автору решения. Автор решения не гарантирует стабильную работу данного бота и не отвечает за контент в нем
Воспользоваться ручкой POST /clients/bulk
и зарегистрироваться в системе
Воспользоваться ручкой GET /clients/{clientId}
и получить информацию о своем профиле
Воспользоваться ручкой GET /ads
и получить наиболее подходящее рекламное объявление
Воспользоваться ручкой POST /ads/{adId}/click
и зафиксировать переход по рекламному объявлению
Воспользоваться ручкой POST /advertisers/bulk
и зарегистрироваться в системе
Воспользоваться ручкой GET /advertisers/{advertiserId}
и получить информацию о своем профиле
Воспользоваться ручкой POST /ml-scores
и добавить метрику ml-скора для клиента
Воспользоваться ручкой POST /advertisers/{advertiserId}/campaigns
и создать рекламную кампанию. При создании кампании
воспользоваться ручкой POST /ai/generate-text
для создания контента рекламной кампании.
Воспользоваться ручкой PATCH /advertisers/{advertiserId}/campaigns/{campaignId}/image
и добавить изображение к рекламе
для привлечения внимания
Воспользоваться ручкой GET /advertisers/{advertiserId}
и получить информацию о всех рекламных кампаниях
Воспользоваться ручкой GET /advertisers/{advertiserId}/campaigns/{campaignId}
и получить информацию о конкретной
рекламной кампании
Воспользоваться ручкой PUT /advertisers/{advertiserId}/campaigns/{campaignId}
и изменить рекламную кампанию
Воспользоваться ручкой DELETE /advertisers/{advertiserId}/campaigns/{campaignId}
и удалить рекламную кампанию
Воспользоваться сервисом grafana
и получить визуализированную статистику по всему рекламному агентству или конкретной
рекламной кампании. Пример ниже
Воспользоваться ручками группы /stats
и получить статистику по рекламодателю или конкретной рекламной кампании в JSON,
например, для последующей обработки
Воспользоваться ручкой POST /time/advance
и сменить текущую дату
Воспользоваться ручкой GET /time
и получить текущую дату
Воспользоваться сервисами grafana
и prometheus
и получить информацию техническую информацию о работе приложения.
Инструкция ниже
Воспользоваться ручкой POST /ai/moderation-campaigns
, чтобы активировать/деактивировать модерацию контента рекламных
кампаний
Быстро получать информацию о сбоях в работе сервисов с помощью alertmanager и иметь возможность быстро устранять их.
В этом разделе я опишу взаимодействие с ботом. Некоторые схожие функции будут объеденины вместе и описаны без скриншотов.
Также для удобства пользователей, бот присылает отформатированные сообщения, в которых по клику можно скопировать отдельные фрагменты
В главном меню бота описаны его возможности, а по кнопкам можно перейти в различные разделы. Рассмотрим их
В данном разделе имеется возможность получить клиента по ID. Пример ответа:
А также можно добавить нового клиента. Пример ответа:
В данном разделе имеется возможность получить рекламодателя по ID, добавить или обновить рекламодателя. Ответы на эти запросы выглядят аналогично схожему функционалу для клиентов.
Также имеется возможность добавить ML-score для пары рекламодатель-клиент. Пример ответа:
В данном разделе собран весь функционал для взаимодействия с рекламными кампаниями
Имеется возможность переключить режим модерации контента с помощью ИИ в рекламных кампаниях.
Для удобства рекламодателей имеется возможность сгенерировать рекламную кампанию. Пример сценария:
Также здесь можно добавить рекламную кампанию, получить все кампании рекламодателя или конкретную кампанию. Ответ бота во всех случаях будет аналогичен скриншоту:
Также доступно обновление таргетинга рекламной кампании, ее изображение, а также удаление рекламной кампании
В данном разделе можно получить рекламное объявление для клиента. В таком случае будет доступен упрощенный интерфейс фиксации клика по рекламе Примеры с изображением и без:
А также можно напрямую зафиксировать клик по рекламе с помощью ID рекламного объявления и клиента (при этом если до этого показа не было, то клик не засчитается). Пример:
В данном разделе можно получить статистику по рекламодателю или конкретной рекламной кампании, а также статистику по дням.
Пример получения статистики (получение статистики по рекламной кампании и рекламодателю несильно отличаются):
Пример получения статистики по дням (получение статистики по рекламной кампании и рекламодателю несильно отличаются):
В данном разделе можно просмотреть текущую дату и сменить ее. Пример взаимодействия (после клика на кнопку "Установить новую дату"):
В боте обрабатываются возможные ошибки, которые возвращает API. Пример:
В Grafana дашборды поделены мной на две группы: business
и technical
, они обозначены тегами.
Ссылка на Grafana - http://localhost:3000/dashboards. Логин/пароль - admin/admin
На таких дашбордах содержится статистика различных бизнес-модулей приложения
Дашборд для рекламодателей условно поделен на 2 части: с общей статистикой и разбивкой по дням. Для улучшения пользовательского опыта вверху дашборда находится выпадающий список, с помощью которого можно выбрать по какому рекламодателю строить графики.
Общая статистика
Статистика по дням
Дашборд со статистикой по рекламном кампании имеет аналогичный вид и функционал с дашбордом для рекламодателей. рекламодателю строить графики.
Эти дашборды содержат более техническую информацию
Дашборд с информацией об API, содержит информацию о количестве запросов, количестве различных групп ответов и другую
полезную информацию
Дашборд с информацией о системе. Например, о нагрузке на процессор или память.
Дашборд с информацией об использовании хранилища S3. Доступен по адресу http://localhost:9001/tools/metrics.
Логин/пароль - root/password
База данных представляет из себя 5 различных таблиц: advertiser
, client
, campaign
, ml_score
и client_to_campaign
.
advertiser - рекламодатель:
id
- айди рекламодателя. Создается автоматически или может быть задан пользователемname
- название рекламодателяcreated_at
- дата и время создания. Создается автоматически
client - клиент:
id
- айди клиента. Создается автоматически или может быть задан пользователемlogin
- логин клиентаage
- возраст клиентаlocation
- локация клиентаgender
- пол клиентаcreated_at
- дата и время создания. Создается автоматически
ml-score - мл-скор:
id
- айди скора. Создается автоматическиclient_id
- айди клиентаadvertiser_id
- айди рекламодателяscore
- значение скораcreated_at
- дата и время создания. Создается автоматически
campaigns - рекламная кампания:
id
- айди кампании. Создается автоматическиadvertiser_id
- айди рекламодателяimpressions_limit
- лимит показовclicks_limit
- лимит кликовcost_per_impression
- цена показаcost_per_click
- цена кликаad_title
- название объявленияad_text
- текст объявленияstart_date
- дата началаend_date
- дата концаgender
- таргетинг, пол целевой аудитории. Необязательное полеage_from
- таргетинг, нижняя граница возраста целевой аудитории. Необязательное полеage_to
- таргетинг, верхняя граница возраста целевой аудитории. Необязательное полеlocation
- таргетинг, локация целевой аудитории. Необязательное полеimage_url
- название изображения объявления в S3-хранилище. Необязательное полеcreated_at
- дата и время создания. Создается автоматически
client_to_campaign - фиксация взаимодействия клиента с рекламной кампанией:
id
- айди сущности. Создается автоматическиclient_id
- айди клиентаcampaign_id
- айди кампанииis_show
- флаг того, показано ли рекламное объявлениеis_click
- флаг того, был ли переход по рекламному объявлению. По умолчанию falsecost_per_impression_for_client
- цена показаcost_per_click_for_client
- цена клика. Необязательное полеdata_show
- дата показа.data_click
- дата клина. Необязательное полеcreated_at
- дата и время создания. Создается автоматически
Также используется хранилище Redis для кэширования даты и состояния модерации.
GET /metrics
- отдает технические метрики для построение дашборда об api
POST /ai/moderation-campaigns
- принимает флаг того, необходимо ли модерировать контент рекламный кампаний. По
умолчанию false
POST /ai/generate-text
- генерирует заголовок и текст рекламной кампании. Учитывает то, что по контексту реклама - это
банеры в интернете и генерирует небольшие тексты
GET /clients/{clientId}
- получение клиента по ID
POST /clients/bulk
- массовое создание/обновление клиентов
GET /advertisers/{advertiserId}
- получение рекламодателя по ID
POST /advertisers/bulk
- массовое создание/обновление рекламодателей
POST /ml-scores
- принимает значение ml-скора пары клиент-рекламодатель
GET /advertisers-ids
- получение ID всех рекламодателей. Используется для упрощения пользовальского опыта при
построении дашбордов
GET /campaigns-ids
- получение ID всех рекламных кампаний. Используется для упрощения пользовальского опыта при
построении дашбордов
POST /advertisers/{advertiserId}/campaigns
- создание рекламной кампании
GET /advertisers/{advertiserId}/campaigns
- получение всех рекламных кампаний рекламодателя
GET /advertisers/{advertiserId}/campaigns/{campaignId}
- получение рекламной кампании
PUT /advertisers/{advertiserId}/campaigns/{campaignId}
- изменение рекламной кампании, часть полей возможно изменить
только до старта кампании
DELETE /advertisers/{advertiserId}/campaigns/{campaignId}
- удаление рекламной кампании
PATCH /advertisers/{advertiserId}/campaigns/{campaignId}/image
- добавление/изменение изображения рекламной кампании
GET /advertisers/{advertiserId}/campaigns/{campaignId}/image
- получить изображение рекламной кампании
GET /ads?client_id={clientId}
- получение рекламного объявления для клиента. О работе алгоритма подбора рекламы
чуть ниже
POST /{adId}/click
- фиксация клика по рекламному объявлению
GET /stats/advertisers/{advertiserId}/campaigns
- получение статистики по всем рекламным кампаниям рекламодателя
GET /stats/advertisers/{advertiserId}/campaigns/daily
- получение агрегированной по дням статистики по всем рекламным
кампаниям рекламодателя
GET /stats/campaigns/{campaignId}
- получение статистики по рекламной кампании
GET /stats/campaigns/{campaignId}/daily
- получение агрегированной по дням статистики по рекламной кампании
POST /time/advance
- изменение текущей даты
GET /time
- получение текущей даты
Для подбора оптимального рекламного объявления разработан следующий алгоритм:
- Фильтруем рекламные кампании по таргету и тому, что они проходят в текущую дату. Оставляем только подходящие
- Фильтруем по ранее непоказанным кампаниям. Оставляем только подходящие
- Фильтруем по количеству показов. Если есть кампании, для
которых
количество показов с учетом текущего показа <= 1.5 * лимит показов
, то оставляет только их. Иначе возвращает ошибку 404 - Выдает пользователю рекламу, для которой максимален показатель
score
, рассчитывающийся по следующей формуле
scorei = 0.25 * norm_ml_scorei + 0.65 * (cost_per_impressioni + norm_ml_score
i * cost_per_click_i) / max_cost - 0.75 * (penalty_impressionsi + penalty_clicksi) -
показатель score
для i-ого объявления
norm_ml_scorei = ml_scorei / ml_scoremax - нормированное на максимальное значение ml_score значение ml_score i-ого объявления
max_cost = cost_per_impressionmax + cost_per_clickmax - максимальная стоимость за показ и клик среди всех подходящих под фильтры объявлений
penalty_impressionsi = (impressionsi - impressions_limiti) / impressions_limit
i - штраф за превышение лимита показов, если количество показов меньше лимита, то положительно влиет на
показатель score
, если больше - отрицательно
penalty_clicksi = (clicksi - clicks_limiti) / clicks_limiti - штраф за
превышение лимита кликов, если количество кликов меньше лимита, то положительно влиет на показатель score
, если
больше - отрицательно
Нормирование для всех слагаемых в формуле
score
необходимо для того, чтобы иметь возможность корректно (не имея перекоса в какую либо сторону из-за несоизмеримых значений) складывать их между собой
В качестве LLM для внедрения в проект выбрана YandexGPT 4 Lite. Она обладает хорошим качеством и высокой скоростью генерации (источник)
По умолчанию модерация отключена для того, чтобы не препятсвовать автоматическим тестам. Ее можно включить, послав
запрос
POST /ai/moderation-campaigns
с телом {"current_state": true}
. После этого при регистрации или изменении рекламных
кампании их содержание будет модерироваться. Модерация проходит с помощью YandexGPT и занимает несколько секунд.
Использование нейросети покрывает бОльшую часть необходимой модерации, а также учитывает контекст и минимизирует ложные
срабатывания. Ознакомиться с промптом можно в файле
Текст для рекламной кампании можно сгенерировать с помощью эндпоинта POST /ai/generate-text
.
При этом тело запроса может содержать 4 параметра:
{
"product": "название продукта",
"advertiser_name": "название рекламодателя",
"audience": "целевая аудитория",
"target": "целевое действие"
}
Первые два поля product
и advertiser_name
указать обязательно, а поля audience
и target
необязательны. При
этом если audience
и target
не переданы, то по умолчанию они равны audience
= охвати как можно больше людей
и target
= покупка
.
Генерация текста займет несколько секунд, при этом результат будет адаптирован под контекст того, что реклама показывается в качестве рекламных банеров, и намеренно имеет небольшую длину. Пример реального ответа:
{
"title": "Вкусные грузинские пельмени в ресторане 'Никития'",
"text": "Попробуйте наши сочные и ароматные грузинские пельмени! Закажите прямо сейчас"
}
Ознакомиться с промптом можно в файле
Тесты реализованы в помощью библиотеки pytest
, e2e-тесты полностью тестируют модули и ручки от начала до конца для
обеспечения контролируемого поведения работы бэкенда. Тесты охватывают большинство сценариев работы бэкенда.
Результаты e2e-тестирования можно увидеть в контейнере test
в докер-композе
Покрытие e2e-тестами на данный момент: 80%