Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement purchase intent classifier for brave ads 8047 #4607

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ test("brave_unit_tests") {
"//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/ads_per_day_frequency_cap_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/frequency_capping/permission_rules/ads_per_hour_frequency_cap_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/sorts/ads_history_sort_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/purchase_intent/funnel_sites_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/purchase_intent/keywords_unittest.cc",
"//brave/vendor/bat-native-ads/src/bat/ads/internal/purchase_intent/purchase_intent_classifier_unittest.cc",
]
}

Expand Down
16 changes: 16 additions & 0 deletions vendor/bat-native-ads/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ source_set("headers") {
"include/bat/ads/ads_history.h",
"include/bat/ads/bundle_state.h",
"include/bat/ads/category_content.h",
"include/bat/ads/purchase_intent_signal_history.h",
"include/bat/ads/client_info_platform_type.h",
"include/bat/ads/client_info.h",
"include/bat/ads/confirmation_type.h",
Expand Down Expand Up @@ -104,6 +105,7 @@ source_set("ads") {
"src/bat/ads/ads_history.cc",
"src/bat/ads/bundle_state.cc",
"src/bat/ads/category_content.cc",
"src/bat/ads/purchase_intent_signal_history.cc",
"src/bat/ads/client_info.cc",
"src/bat/ads/confirmation_type.cc",
"src/bat/ads/creative_ad_notification_info.cc",
Expand Down Expand Up @@ -219,6 +221,20 @@ source_set("ads") {
"src/bat/ads/internal/time.h",
"src/bat/ads/internal/uri_helper.cc",
"src/bat/ads/internal/uri_helper.h",
"src/bat/ads/internal/purchase_intent/funnel_site_info.cc",
"src/bat/ads/internal/purchase_intent/funnel_site_info.h",
"src/bat/ads/internal/purchase_intent/funnel_sites.cc",
"src/bat/ads/internal/purchase_intent/funnel_sites.h",
"src/bat/ads/internal/purchase_intent/funnel_keyword_info.cc",
"src/bat/ads/internal/purchase_intent/funnel_keyword_info.h",
"src/bat/ads/internal/purchase_intent/segment_keyword_info.cc",
"src/bat/ads/internal/purchase_intent/segment_keyword_info.h",
"src/bat/ads/internal/purchase_intent/keywords.cc",
"src/bat/ads/internal/purchase_intent/keywords.h",
"src/bat/ads/internal/purchase_intent/purchase_intent_classifier.cc",
"src/bat/ads/internal/purchase_intent/purchase_intent_classifier.h",
"src/bat/ads/internal/purchase_intent/purchase_intent_signal_info.cc",
"src/bat/ads/internal/purchase_intent/purchase_intent_signal_info.h",
]

deps = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BAT_ADS_PURCHASE_INTENT_SIGNAL_HISTORY_H_
#define BAT_ADS_PURCHASE_INTENT_SIGNAL_HISTORY_H_

#include <stdint.h>
#include <string>
#include <map>
#include <deque>

#include "bat/ads/export.h"
#include "bat/ads/result.h"

namespace ads {

struct ADS_EXPORT PurchaseIntentSignalHistory {
PurchaseIntentSignalHistory();
PurchaseIntentSignalHistory(
const PurchaseIntentSignalHistory& properties);
~PurchaseIntentSignalHistory();

bool operator==(
const PurchaseIntentSignalHistory& rhs) const;

bool operator!=(
const PurchaseIntentSignalHistory& rhs) const;

std::string ToJson() const;
Result FromJson(
const std::string& json,
std::string* error_description = nullptr);

uint64_t timestamp_in_seconds;
uint16_t weight = 0;
};

using PurchaseIntentSignalSegmentHistoryList =
std::deque<PurchaseIntentSignalHistory>;
using PurchaseIntentSignalSegmentHistoryMap =
std::map<std::string, PurchaseIntentSignalSegmentHistoryList>;

} // namespace ads

#endif // BAT_ADS_PURCHASE_INTENT_SIGNAL_HISTORY_H_
86 changes: 78 additions & 8 deletions vendor/bat-native-ads/src/bat/ads/internal/ads_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "bat/ads/ads_history.h"
#include "bat/ads/confirmation_type.h"
#include "bat/ads/ad_notification_info.h"

#include "bat/ads/purchase_intent_signal_history.h"
#include "bat/ads/internal/ads_impl.h"
#include "bat/ads/internal/classification_helper.h"
#include "bat/ads/internal/locale_helper.h"
Expand All @@ -41,6 +41,8 @@
#include "bat/ads/internal/frequency_capping/permission_rules/ads_per_day_frequency_cap.h"
#include "bat/ads/internal/frequency_capping/permission_rules/ads_per_hour_frequency_cap.h"
#include "bat/ads/internal/sorts/ads_history_sort_factory.h"
#include "bat/ads/internal/purchase_intent/purchase_intent_signal_info.h"
#include "bat/ads/internal/purchase_intent/purchase_intent_classifier.h"

#include "base/guid.h"
#include "base/rand_util.h"
Expand Down Expand Up @@ -89,6 +91,9 @@ AdsImpl::AdsImpl(AdsClient* ads_client)
ad_conversions_(std::make_unique<AdConversions>(
this, ads_client, client_.get())),
user_model_(nullptr),
purchase_intent_classifier_(std::make_unique<PurchaseIntentClassifier>(
kPurchaseIntentSignalLevel, kPurchaseIntentClassificationThreshold,
kPurchaseIntentSignalDecayTimeWindow)),
is_initialized_(false),
is_confirmations_ready_(false),
sustained_ad_notification_interaction_timer_id_(0),
Expand Down Expand Up @@ -658,6 +663,8 @@ void AdsImpl::OnPageLoaded(

CheckAdConversion(url);

ExtractPurchaseIntentSignal(url);

if (helper::Uri::MatchesDomainOrHost(url,
last_shown_ad_notification_.target_url)) {
BLOG(INFO) << "Site visited " << url
Expand Down Expand Up @@ -704,6 +711,39 @@ void AdsImpl::OnPageLoaded(
<< previous_tab_url_;
}

void AdsImpl::ExtractPurchaseIntentSignal(
const std::string& url) {
if (!ShouldClassifyPagesIfTargeted()) {
return;
}

if (!TestSearchState(url) &&
helper::Uri::MatchesDomainOrHost(url, previous_tab_url_)) {
return;
}

PurchaseIntentSignalInfo purchase_intent_signal =
purchase_intent_classifier_->ExtractIntentSignal(url);

if (purchase_intent_signal.segments.empty() &&
purchase_intent_signal.timestamp_in_seconds == 0) {
return;
}

GeneratePurchaseIntentSignalHistoryEntry(purchase_intent_signal);
BLOG(INFO) << "Purchase intent signal extracted for " << url;
}

void AdsImpl::GeneratePurchaseIntentSignalHistoryEntry(
const PurchaseIntentSignalInfo& purchase_intent_signal) {
for (const auto& segment : purchase_intent_signal.segments) {
PurchaseIntentSignalHistory history;
history.timestamp_in_seconds = purchase_intent_signal.timestamp_in_seconds;
history.weight = purchase_intent_signal.weight;
client_->AppendToPurchaseIntentSignalHistoryForSegment(segment, history);
}
}

void AdsImpl::CheckAdConversion(
const std::string& url) {
DCHECK(!url.empty());
Expand Down Expand Up @@ -838,8 +878,8 @@ std::string AdsImpl::ClassifyPage(
return winning_category;
}

std::vector<std::string> AdsImpl::GetWinningCategories() {
std::vector<std::string> winning_categories;
WinningCategoryList AdsImpl::GetWinningCategories() {
WinningCategoryList winning_categories;

if (!ShouldClassifyPagesIfTargeted()) {
return winning_categories;
Expand Down Expand Up @@ -929,6 +969,22 @@ AdsImpl::GetPageScoreCache() const {
return page_score_cache_;
}

PurchaseIntentWinningCategoryList
AdsImpl::GetWinningPurchaseIntentCategories() {
PurchaseIntentWinningCategoryList winning_categories;

PurchaseIntentSignalSegmentHistoryMap purchase_intent_signal_history =
client_->GetPurchaseIntentSignalHistory();
if (purchase_intent_signal_history.empty()) {
return winning_categories;
}

winning_categories = purchase_intent_classifier_->GetWinningCategories(
purchase_intent_signal_history, kPurchaseIntentMaxSegments);

moritzhaller marked this conversation as resolved.
Show resolved Hide resolved
return winning_categories;
}

void AdsImpl::TestShoppingData(
const std::string& url) {
if (!IsInitialized()) {
Expand Down Expand Up @@ -1088,12 +1144,24 @@ void AdsImpl::ServeAdNotificationIfReady(
}
}

auto categories = GetWinningCategories();
CategoryList categories = GetCategoriesToServeAd();
ServeAdNotificationFromCategories(categories);
}

CategoryList AdsImpl::GetCategoriesToServeAd() {
CategoryList categories;
WinningCategoryList contextual_categories = GetWinningCategories();
categories.insert(categories.end(),
contextual_categories.begin(), contextual_categories.end());
PurchaseIntentWinningCategoryList purchase_intent_categories =
GetWinningPurchaseIntentCategories();
categories.insert(categories.end(),
purchase_intent_categories.begin(), purchase_intent_categories.end());
return categories;
}

void AdsImpl::ServeAdNotificationFromCategories(
const std::vector<std::string>& categories) {
const CategoryList& categories) {
std::string catalog_id = bundle_->GetCatalogId();
if (catalog_id.empty()) {
FailedToServeAdNotification("No ad catalog");
Expand All @@ -1118,7 +1186,7 @@ void AdsImpl::ServeAdNotificationFromCategories(

void AdsImpl::OnServeAdNotificationFromCategories(
const Result result,
const std::vector<std::string>& categories,
const CategoryList& categories,
const CreativeAdNotificationList& ads) {
auto eligible_ads = GetEligibleAds(ads);
if (!eligible_ads.empty()) {
Expand All @@ -1132,6 +1200,8 @@ void AdsImpl::OnServeAdNotificationFromCategories(
BLOG(INFO) << " " << category;
}

// TODO(https://github.com/brave/brave-browser/issues/8486): Brave Ads
// Purchase Intent segments should not fall back to parent segments
if (ServeAdNotificationFromParentCategories(categories)) {
return;
}
Expand All @@ -1140,8 +1210,8 @@ void AdsImpl::OnServeAdNotificationFromCategories(
}

bool AdsImpl::ServeAdNotificationFromParentCategories(
const std::vector<std::string>& categories) {
std::vector<std::string> parent_categories;
const CategoryList& categories) {
CategoryList parent_categories;
for (const auto& category : categories) {
auto pos = category.find_last_of(kCategoryDelimiter);
if (pos == std::string::npos) {
Expand Down
17 changes: 15 additions & 2 deletions vendor/bat-native-ads/src/bat/ads/internal/ads_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
#include "bat/ads/internal/ad_conversions.h"
#include "bat/ads/internal/ad_notification_result_type.h"
#include "bat/ads/internal/ad_notifications.h"

#include "bat/usermodel/user_model.h"
#include "bat/ads/internal/purchase_intent/purchase_intent_classifier.h"

namespace ads {

using WinningCategoryList = std::vector<std::string>;
using CategoryList = std::vector<std::string>;

class Client;
class Bundle;
class AdsServe;
Expand All @@ -37,6 +40,8 @@ class AdConversions;
class FrequencyCapping;
class ExclusionRule;
class PermissionRule;
class PurchaseIntentClassifier;
struct PurchaseIntentSignalInfo;

class AdsImpl : public Ads {
public:
Expand Down Expand Up @@ -153,6 +158,11 @@ class AdsImpl : public Ads {
const std::string& url,
const std::string& content) override;

void ExtractPurchaseIntentSignal(
const std::string& url);
void GeneratePurchaseIntentSignalHistoryEntry(
const PurchaseIntentSignalInfo& purchase_intent_signal);

void MaybeClassifyPage(
const std::string& url,
const std::string& content);
Expand All @@ -161,7 +171,8 @@ class AdsImpl : public Ads {
const std::string& url,
const std::string& content);

std::vector<std::string> GetWinningCategories();
WinningCategoryList GetWinningCategories();
PurchaseIntentWinningCategoryList GetWinningPurchaseIntentCategories();
std::string GetWinningCategory(
const std::vector<double>& page_score);

Expand Down Expand Up @@ -208,6 +219,7 @@ class AdsImpl : public Ads {
const Result result,
const std::vector<std::string>& categories,
const CreativeAdNotificationList& ads);
CategoryList GetCategoriesToServeAd();
void ServeAdNotification(
const CreativeAdNotificationList& ads);
void OnServeAdNotification(
Expand Down Expand Up @@ -293,6 +305,7 @@ class AdsImpl : public Ads {
std::unique_ptr<FrequencyCapping> frequency_capping_;
std::unique_ptr<AdConversions> ad_conversions_;
std::unique_ptr<usermodel::UserModel> user_model_;
std::unique_ptr<PurchaseIntentClassifier> purchase_intent_classifier_;

private:
bool is_initialized_;
Expand Down
25 changes: 25 additions & 0 deletions vendor/bat-native-ads/src/bat/ads/internal/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "bat/ads/internal/client.h"

#include "bat/ads/ad_history.h"
#include "bat/ads/purchase_intent_signal_history.h"
#include "bat/ads/internal/classification_helper.h"
#include "bat/ads/internal/filtered_ad.h"
#include "bat/ads/internal/filtered_category.h"
Expand Down Expand Up @@ -80,6 +81,30 @@ std::deque<AdHistory> Client::GetAdsShownHistory() const {
return client_state_->ads_shown_history;
}

void Client::AppendToPurchaseIntentSignalHistoryForSegment(
const std::string& segment,
const PurchaseIntentSignalHistory& history) {
if (client_state_->purchase_intent_signal_history.find(segment) ==
client_state_->purchase_intent_signal_history.end()) {
client_state_->purchase_intent_signal_history.insert({segment, {}});
}

client_state_->purchase_intent_signal_history.at(
segment).push_back(history);

if (client_state_->purchase_intent_signal_history.at(segment).size() >
kMaximumEntriesPerSegmentInPurchaseIntentSignalHistory) {
client_state_->purchase_intent_signal_history.at(segment).pop_back();
}

SaveState();
}

const PurchaseIntentSignalSegmentHistoryMap&
Client::GetPurchaseIntentSignalHistory() const {
return client_state_->purchase_intent_signal_history;
}

AdContent::LikeAction Client::ToggleAdThumbUp(
const std::string& creative_instance_id,
const std::string& creative_set_id,
Expand Down
5 changes: 5 additions & 0 deletions vendor/bat-native-ads/src/bat/ads/internal/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class Client {
void AppendAdHistoryToAdsShownHistory(
const AdHistory& ad_history);
std::deque<AdHistory> GetAdsShownHistory() const;
void AppendToPurchaseIntentSignalHistoryForSegment(
const std::string& segment,
const PurchaseIntentSignalHistory& history);
const PurchaseIntentSignalSegmentHistoryMap&
GetPurchaseIntentSignalHistory() const;
AdContent::LikeAction ToggleAdThumbUp(
const std::string& creative_instance_id,
const std::string& creative_set_id,
Expand Down
Loading