Skip to content

Instantly share code, notes, and snippets.

@fpcMotif
Created October 23, 2018 13:58
Show Gist options
  • Select an option

  • Save fpcMotif/bcc2ec1019c9da158b3d886a591cea8f to your computer and use it in GitHub Desktop.

Select an option

Save fpcMotif/bcc2ec1019c9da158b3d886a591cea8f to your computer and use it in GitHub Desktop.
import random
from facebookads.adobjects.adcreativeobjectstoryspec import AdCreativeObjectStorySpec
from facebookads.adobjects.adcreativelinkdata import AdCreativeLinkData
from ads_app.api import AdsApi
from ads_app.api.objects import Ad, AdLabel, CarouselAd
from sjp_app.documents.sjp_image import SjpImage
from sjp_app.documents.strategy import Strategy
from w4.documents.mongo_job import MongoJob
ads_too_many_matching_filters = []
ads_no_filters_for_job = []
ads_no_filters_for_image = []
ads_unknown_state = []
ads_caroussel = []
def is_wording_matching(filter_set, link_data, job):
"""
Return True if all the `filter_set` wording exactly the
same as the ad woding.
Sometimes some ad do not have all the keys (name, message,
description). For instance check creative 6092189325241.
"""
filter_set_wording = filter_set.get_ad_creative_texts(job, job.job_title_pure)
return all([
link_data[key] == filter_set_wording[key]
for key in filter_set_wording if link_data.get(key)
])
def is_image_matching(filter_set, image_hash):
""""
Return True if the `image_hash` is in the `filter_set`.
"""
return any([
image.facebook_img_hash == image_hash for image in filter_set.images
])
def get_filter_set(strategy, ad, link_data, image_hash, job):
"""
Tries to get the filter set.
"""
default_fs = None
job_fs = set()
for filter_set, filter_jobs in strategy.get_filters_with_their_jobs():
if filter_set.is_default:
default_fs = filter_set
if job in filter_jobs:
job_fs.add(filter_set)
if not job_fs:
print("No filter_set found for this job, you'll be killed one day!!")
ads_no_filters_for_job.append(ad)
return None
if len(job_fs) == 1:
print("Only one filter that's the one <3")
return job_fs.pop()
job_wording_matching_fs = set(
filter_set for filter_set in job_fs if is_wording_matching(filter_set, link_data, job)
)
job_image_matching_fs = set(
filter_set for filter_set in job_fs if is_image_matching(filter_set, image_hash)
)
# If there are several filter set matching then ads ops are A/B testing and the default
# filter set is not the one used.
if len(job_wording_matching_fs) > 1:
job_wording_matching_fs = job_wording_matching_fs - set(default_fs)
if len(job_image_matching_fs) > 1:
job_image_matching_fs = job_image_matching_fs - set(default_fs)
if not job_image_matching_fs:
print("No corresponding image, you need to be paused!!")
ads_no_filters_for_image.append(ad)
return None
if len(job_wording_matching_fs) == 1:
print("Only one filter set has the same wording <3")
return job_wording_matching_fs.pop()
if len(job_image_matching_fs) == 1:
print("Only one filter set has the same image <3")
return job_image_matching_fs.pop()
if len(job_wording_matching_fs) > 1 or len(job_image_matching_fs) > 1:
print("The ad could be in different filter set... we pick one randomly and notify the ops")
all_matching_fs = job_image_matching_fs.union(job_image_matching_fs)
ads_too_many_matching_filters.append(ad)
return random.sample(all_matching_fs, 1)
print("OOOPSY we don't handle that case (yet)")
ads_unknown_state.append(ad)
return None
api = AdsApi()
batch = api.new_batch()
ads = api.account.get_ads(
params={
Ad.Field.effective_status: [
Ad.EffectiveStatus.active,
Ad.EffectiveStatus.pending_review,
Ad.EffectiveStatus.pending_billing_info,
Ad.EffectiveStatus.campaign_paused,
Ad.EffectiveStatus.adset_paused
],
'limit': 500
},
fields=[
Ad.Field.name,
'creative{object_story_spec}', # crucial to have the right Ad classes (carousel)
Ad.Field.adlabels,
Ad.Field.campaign_id
]
)
for ad in ads:
fs_label = None
image_label = None
# checks if we have a any filter set label or image label
for adlabel in ad.get(Ad.Field.adlabels, []):
label_name = adlabel.get('name', '')
if AdLabel.FILTER_SET_LABEL_PREFIX in label_name:
fs_label = label_name
if "img_id=" in label_name:
image_label = label_name
if image_label and fs_label:
print "Ad (%s) already got and image (%s) and filter set (%s) label." % (
ad.get_id(), image_label, fs_label
)
continue
print "Ad (%s) got missing label: image (%s), filter set (%s)." % (
ad.get_id(), image_label, fs_label
)
creative = ad.ensure_field(ad.Field.creative)
fb_campaign_id = ad.get(Ad.Field.campaign_id)
strategy = Strategy.objects(fb_campaign_id=fb_campaign_id).first()
if not strategy:
print "Lovely some custom ads camapign (%s) in the SJP account" % fb_campaign_id
continue
if isinstance(ad, CarouselAd):
print "Ad (%s) is a CarouselAd." % (ad.get_id())
ads_caroussel.append(ad)
job_ids = creative.get_job_ids()
image_hashes = creative.get_image_hashes()
jobs = [
MongoJob.objects(job_id=job_id).first()
for job_id in job_ids
]
# TODO: deal with carousel ad
else:
job_id = ad.get_job_id()
job = MongoJob.objects(job_id=job_id).first()
link_data = creative[creative.Field.object_story_spec][AdCreativeObjectStorySpec.Field.link_data]
image_hash = link_data.get(AdCreativeLinkData.Field.image_hash)
filter_set = get_filter_set(strategy, ad, link_data, image_hash, job)
adlabel_batch = api.new_batch()
if image_hash:
images = SjpImage.objects.filter(facebook_img_hash=image_hash)
if len(images) == 1:
image = images[0]
elif filter_set:
adlabel = AdLabel(parent_id=api.account_id)
adlabel.remote_create(params={
AdLabel.Field.name: AdLabel.IMAGE_LABEL_PREFIX % image.google_id
})
ad.add_adlabel(adlabel)
if not filter_set:
print "No filter set found for Ad(%s)." % (ad.get_id())
adlabel = AdLabel(parent_id=api.account_id)
adlabel.remote_create(params={
AdLabel.Field.name: AdLabel.FILTER_SET_LABEL_PREFIX + str(filter_set.id)
}, batch=adlabel_batch)
ad.add_adlabel(adlabel)
adlabel_batch.execute()
ad_batch = api.new_batch()
ad.remote_update(batch=ad_batch)
ad_batch.execute()
# DEBUGG POST SCRIPT
print len(ads_too_many_matching_filters)
print len(ads_no_filters_for_job)
print len(ads_no_filters_for_image)
print len(ads_unknown_state)
print len(ads_caroussel)
creative = ad.ensure_field(ad.Field.creative)
fb_campaign_id = ad.get(Ad.Field.campaign_id)
strategy = Strategy.objects(fb_campaign_id=fb_campaign_id).first()
job_id = ad.get_job_id()
job = MongoJob.objects(job_id=job_id).first()
link_data = creative[creative.Field.object_story_spec][AdCreativeObjectStorySpec.Field.link_data]
image_hash = link_data[AdCreativeLinkData.Field.image_hash]
filter_set = get_filter_set(strategy, ad, link_data, image_hash, job)
print strategy.id
strategies = set(Strategy.objects(fb_campaign_id=ad.get(Ad.Field.campaign_id)).first() for ad in ads_too_many_matching_filters)
for strategy in strategies:
if not strategy.is_over:
print strategy
print strategy.id
print strategy.state
# EMEA - SJP - Manpower France - Logistique Vente Privee - 201801 - MF - RT - St-Vulbas - PRIO_1 - Lead_Ads
# 5a5f7f89baeb406179449474
# active
# EMEA - SJP - Start People - BTP - 201711 - MF - RT - Multiple Locations - Vertical - PRIO_1 - Lead_Ads - Delivering
# 5a267f55f32a5c691ff0ff01
# active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment