|
@@ -6,7 +6,7 @@ import pandas as pd
|
|
|
import os
|
|
|
import yaml
|
|
|
import requests
|
|
|
-from commonFunc import get_db_engine, is_contains_gender, is_contains_age
|
|
|
+from commonFunc import get_db_engine, is_contains_gender, is_contains_age, is_contains_region
|
|
|
from config.url import create_campaign_url, create_group_and_creative_url, headers
|
|
|
|
|
|
with open('config/config.yaml', mode='r', encoding='utf-8') as f:
|
|
@@ -39,9 +39,13 @@ class GetTargetAndAssemblyParameters(object):
|
|
|
self.engine = None
|
|
|
self.get_database_engine()
|
|
|
self.signature_target_combine = None
|
|
|
+ self.final_target_combine = []
|
|
|
self.advertiser_strategy_id = None
|
|
|
self.advertiser_strategy = {}
|
|
|
- self.ai_strategy_uuid = None
|
|
|
+ self.ai_strategy_uuid = str(uuid.uuid4())
|
|
|
+ self.request_data = None
|
|
|
+ self.campaign_id = None
|
|
|
+ self.operation_type = 1 # 新增广告组
|
|
|
|
|
|
def get_database_engine(self):
|
|
|
# 数据库连接引擎,依据开发环境/生产环境 进行切换
|
|
@@ -78,8 +82,9 @@ class GetTargetAndAssemblyParameters(object):
|
|
|
"message": "SUCCESS"}
|
|
|
"""
|
|
|
# 1、请求创建广告计划的接口
|
|
|
+ campaign_name = self.advertiser_strategy['campaign_name'] + '_优质定向'
|
|
|
create_campaign_request_data = {'account_id': self.account_id,
|
|
|
- 'campaign_name': self.advertiser_strategy['campaign_name'] + '_优质定向',
|
|
|
+ 'campaign_name': campaign_name,
|
|
|
'type': self.advertiser_strategy['campaign_type']}
|
|
|
|
|
|
request = requests.post(url=create_campaign_url,
|
|
@@ -92,13 +97,14 @@ class GetTargetAndAssemblyParameters(object):
|
|
|
'campaign_uuid': str(uuid.uuid4()),
|
|
|
'account_id': self.account_id,
|
|
|
'ai_strategy_uuid': self.ai_strategy_uuid,
|
|
|
- 'campaign_name': self.advertiser_strategy['campaign_name'],
|
|
|
+ 'campaign_name': campaign_name,
|
|
|
'campaign_type': self.advertiser_strategy['campaign_type'],
|
|
|
'create_time': datetime.datetime.now()
|
|
|
}
|
|
|
res = 0
|
|
|
if response_data['code'] == 0:
|
|
|
- campaign_info_to_db['campaign_id'] = response_data['data'].get('campaign_id', None)
|
|
|
+ self.campaign_id = response_data['data'].get('campaign_id', None)
|
|
|
+ campaign_info_to_db['campaign_id'] = self.campaign_id
|
|
|
campaign_info_to_db['campaign_create_time'] = response_data['data'].get('campaign_create_time', None)
|
|
|
campaign_info_to_db['status'] = response_data.get('code', None)
|
|
|
campaign_info_to_db['message'] = response_data.get('message', None)
|
|
@@ -119,6 +125,7 @@ class GetTargetAndAssemblyParameters(object):
|
|
|
def get_signature_and_target(self):
|
|
|
"""
|
|
|
从 ctop_ai_kuaishou_signature_recommended_target_combine 表中读取素材和对应的定向
|
|
|
+ 读取配置文件的条件,筛选出符合条件的定向组合
|
|
|
"""
|
|
|
sql = """
|
|
|
select * from ctop_ai_kuaishou_signature_recommended_target_combine where project_id = %s and stat_date = curdate()
|
|
@@ -144,39 +151,226 @@ class GetTargetAndAssemblyParameters(object):
|
|
|
"""
|
|
|
拼接好的组创意的参数写入到 ctop_ai_kuaishou_intelligence_strategy 中的 ai_strategy_request_content
|
|
|
"""
|
|
|
- pass
|
|
|
+ intelligence_strategy_dict = \
|
|
|
+ {
|
|
|
+ 'ai_strategy_uuid': self.ai_strategy_uuid,
|
|
|
+ 'advertiser_strategy_id': self.advertiser_strategy_id,
|
|
|
+ 'account_id': self.account_id,
|
|
|
+ 'ai_strategy_request_content': str(self.request_data),
|
|
|
+ 'ai_strategy_remark': '优质定向组合',
|
|
|
+ 'create_time': datetime.datetime.now()
|
|
|
+ }
|
|
|
+ df = pd.DataFrame.from_dict(intelligence_strategy_dict, orient='index').T
|
|
|
+ df.to_sql(name="ctop_ai_kuaishou_intelligence_strategy",
|
|
|
+ con=self.engine,
|
|
|
+ if_exists='append',
|
|
|
+ index=False)
|
|
|
|
|
|
- def get_target_intersection(self):
|
|
|
+ def target_combine_is_subset(self):
|
|
|
"""
|
|
|
- 两个表中读取的定向取交集,还是子集?
|
|
|
- age struct 可选 自定义年龄段 不传值表示不限,传值具体见下方表格;与ages_range不能同时传
|
|
|
- age 字段 类型 是否必填 说明 备注
|
|
|
- min int 必填 年龄最小限制 年龄区间最小为18岁
|
|
|
- max int 必填 年龄最大限制 年龄区间最大为55岁,且年龄最大限制须大于等于年龄最小限制
|
|
|
-
|
|
|
- ages_range int[] 可选 固定年龄段 与age不能同时传;【18:表示18-23岁】;【24:表示24-30岁】;【31:表示31-40岁】;【41:表示41-49岁】;【50:表示50-100岁】
|
|
|
ctop_ai_kuaishou_signature_recommended_target_combine 表中的 city 和 province 都对应 self.advertiser_strategy 的 region [] varchar
|
|
|
age 对应 ages_range [] varchar
|
|
|
client 对应 platform_os int
|
|
|
business_interest 对应 business_interest varchar
|
|
|
gender 对应 gender int
|
|
|
-
|
|
|
"""
|
|
|
for item in self.signature_target_combine:
|
|
|
- gender_bool, gender_dict = is_contains_age(item['gender'], self.advertiser_strategy['gender'])
|
|
|
- age_bool, age_dict = is_contains_age(item['age'], self.advertiser_strategy['age'])
|
|
|
+ gender_bool, gender_dict = is_contains_gender(item['gender'], self.advertiser_strategy['gender'])
|
|
|
+ age_bool, age_dict = is_contains_age(item['age'],
|
|
|
+ self.advertiser_strategy['age_min'],
|
|
|
+ self.advertiser_strategy['age_max'],
|
|
|
+ self.advertiser_strategy['ages_range'])
|
|
|
+ region_bool, region_dict = is_contains_region(item['city'], self.advertiser_strategy['region'])
|
|
|
|
|
|
- if gender_bool & age_bool:
|
|
|
+ if gender_bool & age_bool & region_bool:
|
|
|
target_combine = {'signature': item['signature']}
|
|
|
target_combine.update(gender_dict)
|
|
|
target_combine.update(age_dict)
|
|
|
+ target_combine.update(region_dict)
|
|
|
+ self.final_target_combine.append(target_combine)
|
|
|
else:
|
|
|
+ # TODO logger
|
|
|
pass
|
|
|
|
|
|
- pass
|
|
|
-
|
|
|
def assembly_group_and_creative_params(self):
|
|
|
"""
|
|
|
拼接参数,请求创建接口
|
|
|
"""
|
|
|
- pass
|
|
|
+ group_params, group_params_to_db = self.get_group_params()
|
|
|
+ creative_params = self.get_creative_params()
|
|
|
+
|
|
|
+ self.request_data['group_list'] = []
|
|
|
+ group_cnt = 1
|
|
|
+ for item in self.final_target_combine:
|
|
|
+ group_uuid = str(uuid.uuid4())
|
|
|
+ group_name = group_params['unit_name']
|
|
|
+
|
|
|
+ # 1-2 获取素材名称
|
|
|
+ sql = """select * from ctop_kuaishou_video_get where account_id = %s and signature = '%s' limit 1""" % \
|
|
|
+ (self.account_id, item['signature'])
|
|
|
+ signature_name_df = pd.read(sql, self.engine)
|
|
|
+ signature_name = signature_name_df['photo_name'].values[0]
|
|
|
+ group_name.replace('{{素材名称}}', signature_name)
|
|
|
+
|
|
|
+ group_name = group_name + '_优质定向' + '_' + str(group_cnt)
|
|
|
+ group_cnt += 1
|
|
|
+
|
|
|
+ def get_group_params(self):
|
|
|
+ group_params = {'unit_name': self.advertiser_strategy.get('group_name'),
|
|
|
+ 'put_status': self.advertiser_strategy.get('group_status'),
|
|
|
+ 'template_id': self.advertiser_strategy.get('template_id'),
|
|
|
+ 'bid_type': self.advertiser_strategy.get('bid_type'),
|
|
|
+ 'use_app_market': self.advertiser_strategy.get('use_app_market'),
|
|
|
+ 'app_store': eval(self.advertiser_strategy.get('app_store')) if self.advertiser_strategy.get('app_store') else None,
|
|
|
+ 'bid': self.advertiser_strategy.get('bid'),
|
|
|
+ 'cpa_bid': self.advertiser_strategy.get('cpa_bid'),
|
|
|
+ 'smart_bid': self.advertiser_strategy.get('smart_bid'),
|
|
|
+ 'ocpx_action_type': self.advertiser_strategy.get('ocpx_action_type'),
|
|
|
+ 'deep_conversion_type': self.advertiser_strategy.get('deep_conversion_type'),
|
|
|
+ 'scene_id': eval(self.advertiser_strategy.get('scene_id')) if self.advertiser_strategy.get('scene_id') else None,
|
|
|
+ 'unit_type': self.advertiser_strategy.get('unit_type'),
|
|
|
+ 'begin_time': self.advertiser_strategy.get('begin_time'),
|
|
|
+ 'end_time': self.advertiser_strategy.get('end_time'),
|
|
|
+ 'schedule_time': self.advertiser_strategy.get('schedule_time'),
|
|
|
+ 'day_budget': self.advertiser_strategy.get('unit_day_budget'),
|
|
|
+ 'day_budget_schedule': eval(self.advertiser_strategy.get('unit_day_budget_schedule'))
|
|
|
+ if self.advertiser_strategy.get('unit_day_budget_schedule') else None,
|
|
|
+ 'convert_id': self.advertiser_strategy.get('convert_id'),
|
|
|
+ 'url_type': self.advertiser_strategy.get('url_type'),
|
|
|
+ 'web_uri_type': self.advertiser_strategy.get('web_uri_type'),
|
|
|
+ 'url': self.advertiser_strategy.get('url'),
|
|
|
+ 'schema_uri': self.advertiser_strategy.get('schema_uri'),
|
|
|
+ 'app_id': self.advertiser_strategy.get('app_id'),
|
|
|
+ 'show_mode': self.advertiser_strategy.get('show_mode'),
|
|
|
+ 'speed': self.advertiser_strategy.get('speed'),
|
|
|
+ 'site_type': self.advertiser_strategy.get('site_type'),
|
|
|
+ 'gift_data': self.advertiser_strategy.get('gift_data'),
|
|
|
+ 'video_landing_page': self.advertiser_strategy.get('video_landing_page'),
|
|
|
+ 'auto_target': self.advertiser_strategy.get('auto_target'),
|
|
|
+ 'auto_create_photo': self.advertiser_strategy.get('auto_create_photo'),
|
|
|
+ 'item_id': self.advertiser_strategy.get('item_id'),
|
|
|
+ 'merchant_item_put_type ': self.advertiser_strategy.get('merchant_item_put_type '),
|
|
|
+ 'fiction_id': self.advertiser_strategy.get('fiction_id'),
|
|
|
+ 'smart_cover': self.advertiser_strategy.get('smart_cover'),
|
|
|
+ 'asset_mining': self.advertiser_strategy.get('asset_mining'),
|
|
|
+ 'consult_id': self.advertiser_strategy.get('consult_id'),
|
|
|
+ 'adv_card_option': self.advertiser_strategy.get('adv_card_option'),
|
|
|
+ 'adv_card_list': self.advertiser_strategy.get('adv_card_list'),
|
|
|
+ 'card_type': self.advertiser_strategy.get('card_type'),
|
|
|
+ 'merchandise_id': self.advertiser_strategy.get('merchandise_id'),
|
|
|
+ 'merchandise_type': self.advertiser_strategy.get('merchandise_type'),
|
|
|
+ 'intention_target': self.advertiser_strategy.get('intention_target'),
|
|
|
+ 'dpa_unit_param': self.advertiser_strategy.get('dpa_unit_param'),
|
|
|
+ 'region': self.advertiser_strategy.get('region'),
|
|
|
+ 'district_ids': self.advertiser_strategy.get('district_ids'),
|
|
|
+ 'user_type': self.advertiser_strategy.get('user_type'),
|
|
|
+ 'age_min': self.advertiser_strategy.get('age_min'),
|
|
|
+ 'age_max': self.advertiser_strategy.get('age_min'),
|
|
|
+ 'ages_range': eval(self.advertiser_strategy.get('ages_range'))
|
|
|
+ if self.advertiser_strategy.get('ages_range') else None,
|
|
|
+ 'gender': self.advertiser_strategy.get('gender'),
|
|
|
+ 'platform_os': self.advertiser_strategy.get('platform_os'),
|
|
|
+ 'android_osv': self.advertiser_strategy.get('android_osv'),
|
|
|
+ 'ios_osv': self.advertiser_strategy.get('ios_osv'),
|
|
|
+ 'network': self.advertiser_strategy.get('network'),
|
|
|
+ 'device_brand': eval(self.advertiser_strategy.get('device_brand'))
|
|
|
+ if self.advertiser_strategy.get('device_brand') else None,
|
|
|
+ 'device_price': self.advertiser_strategy.get('device_price'),
|
|
|
+ 'business_interest_type': self.advertiser_strategy.get('business_interest_type'),
|
|
|
+ 'business_interest': eval(self.advertiser_strategy.get('business_interest'))
|
|
|
+ if self.advertiser_strategy.get('business_interest') else None,
|
|
|
+ 'fans_star': eval(self.advertiser_strategy.get('fans_star'))
|
|
|
+ if self.advertiser_strategy.get('fans_star') else None,
|
|
|
+ 'interest_video': eval(self.advertiser_strategy.get('interest_video'))
|
|
|
+ if self.advertiser_strategy.get('interest_video') else None,
|
|
|
+ 'app_interest': eval(self.advertiser_strategy.get('app_interest'))
|
|
|
+ if self.advertiser_strategy.get('app_interest') else None,
|
|
|
+ 'app_interest_ids': eval(self.advertiser_strategy.get('app_interest_ids'))
|
|
|
+ if self.advertiser_strategy.get('app_interest_ids') else None,
|
|
|
+ 'app_ids': eval(self.advertiser_strategy.get('app_ids'))
|
|
|
+ if self.advertiser_strategy.get('app_ids') else None,
|
|
|
+ 'filter_converted_level ': self.advertiser_strategy.get('filter_converted_level '),
|
|
|
+ 'population': eval(self.advertiser_strategy.get('population'))
|
|
|
+ if self.advertiser_strategy.get('population') else None,
|
|
|
+ 'exclude_population': eval(self.advertiser_strategy.get('exclude_population'))
|
|
|
+ if self.advertiser_strategy.get('exclude_population') else None,
|
|
|
+ 'paid_audience': eval(self.advertiser_strategy.get('paid_audience'))
|
|
|
+ if self.advertiser_strategy.get('paid_audience') else None,
|
|
|
+ 'is_open': self.advertiser_strategy.get('is_open'),
|
|
|
+ 'no_age_break': self.advertiser_strategy.get('no_age_break'),
|
|
|
+ 'no_gender_break': self.advertiser_strategy.get('no_gender_break'),
|
|
|
+ 'no_area_break': self.advertiser_strategy.get('no_area_break'),
|
|
|
+ 'behavior_interest': self.advertiser_strategy.get('behavior_interest')
|
|
|
+ }
|
|
|
+
|
|
|
+ # smart_cover 和 asset_mining 需要将0/1 转化为 False/True
|
|
|
+ group_params['smart_cover'] = True if group_params.get('smart_cover', 0) == 1 else False
|
|
|
+ group_params['asset_mining'] = True if group_params.get('asset_mining', 0) == 1 else False
|
|
|
+
|
|
|
+ # 广告组名称,通配符的替换
|
|
|
+ # 900299 -{{广告位置}}--{{创意制作方式}}--{{日期}}- (日期、素材名称、应用名称、应用标记、创意制作方式、广告位置)
|
|
|
+ # 1-1 获取应用标记和应用名称
|
|
|
+ sql = """select app_version, app_name from ctop_kuaishou_app_list where app_id = % limit 1""" % \
|
|
|
+ group_params.get('app_id')
|
|
|
+ app_info_df = pd.read_sql(sql, self.engine)
|
|
|
+ app_version = app_info_df['app_version'].values[0]
|
|
|
+ app_name = app_info_df['app_name'].values[0]
|
|
|
+ # 1-2 素材名称, 在拼装广告组和创意层级函数中获取
|
|
|
+ # 1-3 获取创意制作方式
|
|
|
+ unit_type = '自定义' if group_params.get('unit_type') == 4 \
|
|
|
+ else ('程序化创意' if group_params.get('unit_type') == 5 else '程序化创意2.0')
|
|
|
+ # 1-4 获取广告位置
|
|
|
+ scene_id_dict = {1: '优选广告位',
|
|
|
+ 3: '视频播放页广告-便利贴广告',
|
|
|
+ 5: '联盟广告',
|
|
|
+ 6: '上下滑大屏广告',
|
|
|
+ 7: '信息流广告',
|
|
|
+ 10: '联盟场景'}
|
|
|
+ scene_id = '+'.join([scene_id_dict[item] for item in group_params.get('scene_id')])
|
|
|
+
|
|
|
+ group_name = group_params['group_name'].replace('{{应用标记}}', app_version). \
|
|
|
+ replace('{{应用名称}}', app_name). \
|
|
|
+ replace('{{创意制作方式}}', unit_type). \
|
|
|
+ replace('{{广告位置}}', scene_id)
|
|
|
+ # 1-2 日期, 在拼装广告组和创意层级函数中获取
|
|
|
+ now_date = str(datetime.datetime.now().date())
|
|
|
+ if '日期' in group_params['group_name']:
|
|
|
+ group_name = group_name.replace('{{日期}}', '_' + now_date)
|
|
|
+ else:
|
|
|
+ group_name = group_name + '_' + now_date
|
|
|
+ group_params['unit_name'] = group_name
|
|
|
+
|
|
|
+ # 2 写入数据库的组参数
|
|
|
+ group_params_to_db = group_params.copy()
|
|
|
+ group_params_to_db['group_name'] = group_params_to_db.pop('unit_name')
|
|
|
+ group_params_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid
|
|
|
+ group_params_to_db['account_id'] = self.account_id
|
|
|
+ group_params_to_db['campaign_id'] = self.campaign_id
|
|
|
+ group_params_to_db['operation_type'] = self.operation_type
|
|
|
+ group_params_to_db['status'] = 1
|
|
|
+ group_params_to_db['message'] = None
|
|
|
+
|
|
|
+ return group_params, group_params_to_db
|
|
|
+
|
|
|
+ def get_creative_params(self):
|
|
|
+ creative_params = {'creative_name': self.advertiser_strategy.get('creative_name'),
|
|
|
+ 'put_status': self.advertiser_strategy.get('put_status'),
|
|
|
+ 'action_bar_text': self.advertiser_strategy.get('action_bar_text'),
|
|
|
+ 'description': self.advertiser_strategy.get('description'),
|
|
|
+ 'short_slogan': self.advertiser_strategy.get('short_slogan'),
|
|
|
+ 'sticker_title': self.advertiser_strategy.get('sticker_title'),
|
|
|
+ 'overlay_type': self.advertiser_strategy.get('overlay_type'),
|
|
|
+ 'expose_tag': self.advertiser_strategy.get('expose_tag'),
|
|
|
+ 'new_expose_tag': eval(self.advertiser_strategy.get('new_expose_tag'))
|
|
|
+ if self.advertiser_strategy.get('new_expose_tag') else None,
|
|
|
+ 'site_id': self.advertiser_strategy.get('site_id'),
|
|
|
+ 'click_track_url': self.advertiser_strategy.get('click_track_url'),
|
|
|
+ 'impression_url': self.advertiser_strategy.get('impression_url'),
|
|
|
+ 'ad_photo_played_t3s_url': self.advertiser_strategy.get('ad_photo_played_t3s_url'),
|
|
|
+ 'actionbar_click_url': self.advertiser_strategy.get('actionbar_click_url'),
|
|
|
+ 'creative_category': self.advertiser_strategy.get('creative_category'),
|
|
|
+ 'creative_tag': eval(self.advertiser_strategy.get('creative_tag'))
|
|
|
+ if self.advertiser_strategy.get('creative_tag') else None,
|
|
|
+ 'live_creative_type': self.advertiser_strategy.get('live_creative_type')
|
|
|
+ }
|
|
|
+ return creative_params
|