from typing import Optional, Awaitable import pandas as pd import numpy as np import datetime import pymysql from sqlalchemy import create_engine import simplejson import requests import tornado.web import pandas as pd import json import numpy as np import datetime from sqlalchemy import create_engine from db_config import * import traceback import uuid class AiCallBackAddCreative(tornado.web.RequestHandler): def initialize(self, logger): self.logger = logger def post(self): data = self.request.body data = str(data, 'utf8') data = json.loads(data, encoding='utf8') self.logger.info("*************************************** NEW REQUEST ***************************************") self.logger.info("raw data from request is %s" % data) create_group_and_creative_response_data = None # 1、新增广告组操作 try: if data["operation_type"] == 1: inst = ParseAddCampaignOrAddGroupRequest(data) inst.get_advertiser_strategy_info() inst.write_intelligence_strategy_table() if inst.campaign_id == "" or inst.campaign_id is None: if inst.add_campaign() == -1: self.write(json.dumps({"message": "广告计划创建失败"})) self.flush() return inst.get_group_dict() create_group_and_creative_res = inst.res_data print("create_group_and_creative_res: ", create_group_and_creative_res) request = requests.post(create_group_and_creative_url, create_group_and_creative_res) create_group_and_creative_response_data = simplejson.loads(request.text) except Exception: self.logger.error(traceback.format_exc()) # 返回接口结果 self.write(json.dumps({'account_id': inst.account_id,'ai_strategy_id': inst.ai_strategy_uuid, 'message': create_group_and_creative_response_data})) self.flush() # 该类解析的是 手动请求的新增广告计划或者新增广告组的数据 class ParseAddCampaignOrAddGroupRequest(object): def __init__(self, request_data): self.ai_strategy_uuid = str(uuid.uuid4()) self.request_data = request_data self.video = self.request_data['video'] self.account_id = self.request_data['account_id'] self.campaign_info = self.request_data['campaign_info'] self.campaign_id = self.request_data['campaign_info'].get('campaign_id', None) self.group_info = self.request_data['group_info'] self.creative_info = self.request_data['creative_info'] self.operation_type = self.request_data['operation_type'] self.advertiser_strategy_id = None self.advertiser_strategy = {} self.res_data = {} def get_advertiser_strategy_info(self): """ 获取指定账户下客户的策略信息 为后续的写入库表,校验一致性做准备 :return: """ sql = """ select * from ctop_ai_kuaishou_advertiser_strategy where account_id = %d and status = 1 limit 1 """ % self.account_id advertiser_strategy_df = pd.read_sql(sql, engine) self.advertiser_strategy_id = advertiser_strategy_df['id'].values[0] self.advertiser_strategy = advertiser_strategy_df.T.to_dict()[0] def write_intelligence_strategy_table(self): """ 请求信息写入 ctop_ai_kuaishou_intelligence_strategy 表中 :return: """ 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': 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=engine, if_exists='append', index=False) # 如果手动请求的数据结构中,"campaign" 中的 campaign_id 为空则调用该新增计划方法 def add_campaign(self): """ 新增广告计划 :return: """ # 1、校验请求信息中 有没有 与客户策略信息 中存在冲突的地方 -- 计划层级只判断 campaign_type if self.campaign_info['campaign_type'] != self.advertiser_strategy['campaign_type']: self.logger.info("客户策略的campaign_type: %d 和 AI策略的campaign_type:%d 不一致!" % (self.advertiser_strategy['campaign_type'], self.campaign_info['campaign_type'])) return -1 # TODO 待联调测试 # create_campaign_req_data = { # 'account_id': self.account_id, # 'campaign_name': self.campaign_info['campaign_name'], # 'type': self.campaign_info['campaign_type'] # } # request = requests.post(create_campaign_url, create_campaign_req_data) # res_data = simplejson.loads(request.text) res_data = { "code": 0, "data": { "account_id": 23212, "campaign_id": 30956133, "campaign_create_time": "2021-01-13 13:50:16" }, "message": "SUCCESS"} if res_data['code'] == 0: self.campaign_id = res_data['data']['campaign_id'] campaign_info_to_db = { 'campaign_uuid': str(uuid.uuid4()), 'account_id': self.account_id, 'ai_strategy_uuid': self.ai_strategy_uuid, 'campaign_name': self.campaign_info['campaign_name'], 'campaign_id': self.campaign_id, 'campaign_type': self.campaign_info['campaign_type'], 'operation_type': self.operation_type, 'campaign_create_time': res_data['data']['campaign_create_time'], 'create_time': datetime.datetime.now() } df = pd.DataFrame.from_dict(campaign_info_to_db, orient='index').T df.to_sql(name="ctop_ai_kuaishou_campaign_level_operation_record", con=engine, if_exists='append', index=False) else: self.logger.info("广告计划创建失败:%s" % res_data['message']) return -1 def get_group_dict(self): """ 拼接组和创意层级参数 写入数据库 返回 table_id :return: """ # 1、TODO 校验请求信息中 有没有 与客户策略信息 中存在冲突的地方 -- 暂时不实现 # 客户策略 和 请求信息 都有值 才会进行校验比对操作 -- 不得高于,不得不等于,不得超过集合 # 因此分为3类 字段 # is_equal_cols = ['template_id','bid_type'] # is_less_than_cols = [] # is_contain_cols = [] # # for col in is_equal_cols: # if (self.advertiser_strategy[col] is not None) and \ # (self.group_info.get(col, None) is not None) and \ # (self.group_info.get(col) != self.advertiser_strategy[col]): # return -1 # # for col in is_less_than_cols: # if (self.advertiser_strategy[col] is not None) and \ # (self.group_info.get(col, None) is not None) and \ # (self.group_info.get(col) > self.advertiser_strategy[col]): # return -1 # # for col in is_contain_cols: # if (self.advertiser_strategy[col] is not None) and \ # (self.group_info.get(col, None) is not None) and \ # (self.group_info.get(col) > self.advertiser_strategy[col]): # return -1 basic_group_info = {'template_id': self.advertiser_strategy['template_id'], 'bid_type': self.advertiser_strategy['bid_type'], 'use_app_market': self.advertiser_strategy['use_app_market'], 'app_store': self.advertiser_strategy['app_store'], 'bid': self.advertiser_strategy['bid'], 'cpa_bid': self.advertiser_strategy['cpa_bid'], 'smart_bid': self.advertiser_strategy['smart_bid'], 'ocpx_action_type': self.advertiser_strategy['ocpx_action_type'], 'deep_conversion_type': self.advertiser_strategy['deep_conversion_type'], 'roi_ratio': self.advertiser_strategy['roi_ratio'], 'scene_id': self.advertiser_strategy['scene_id'], 'unit_type': self.advertiser_strategy['unit_type'], 'begin_time': self.advertiser_strategy['begin_time'], 'end_time': self.advertiser_strategy['end_time'], 'schedule_time': self.advertiser_strategy['schedule_time'], 'convert_id': self.advertiser_strategy['convert_id'], 'url_type': self.advertiser_strategy['url_type'], 'web_uri_type': self.advertiser_strategy['web_uri_type'], 'url': self.advertiser_strategy['url'], 'schema_uri': self.advertiser_strategy['schema_uri'], 'app_id': self.advertiser_strategy['app_id'], 'show_mode': self.advertiser_strategy['show_mode'], 'speed': self.advertiser_strategy['speed'], 'site_type': self.advertiser_strategy['site_type'], 'gift_data': self.advertiser_strategy['gift_data'], 'video_landing_page': self.advertiser_strategy['video_landing_page'], 'auto_target': self.advertiser_strategy['auto_target'], 'auto_create_photo': self.advertiser_strategy['auto_create_photo'], 'region': self.advertiser_strategy['region'], 'district_ids': self.advertiser_strategy['district_ids'], 'user_type': self.advertiser_strategy['user_type'], 'age_min': self.advertiser_strategy['age_min'], 'age_max': self.advertiser_strategy['age_max'], 'ages_range': self.advertiser_strategy['ages_range'], 'gender': self.advertiser_strategy['gender'], 'platform_os': self.advertiser_strategy['platform_os'], 'android_osv': self.advertiser_strategy['android_osv'], 'ios_osv': self.advertiser_strategy['ios_osv'], 'network': self.advertiser_strategy['network'], 'device_brand': self.advertiser_strategy['device_brand'], 'device_price': self.advertiser_strategy['device_price'], 'business_interest_type': self.advertiser_strategy['business_interest_type'], 'business_interest': self.advertiser_strategy['business_interest'], 'fans_star': self.advertiser_strategy['fans_star'], 'interest_video': self.advertiser_strategy['interest_video'], 'app_interest': self.advertiser_strategy['app_interest'], 'app_ids': self.advertiser_strategy['app_ids'], 'filter_converted_level': self.advertiser_strategy['filter_converted_level'], 'population': self.advertiser_strategy['population'], 'exclude_population': self.advertiser_strategy['exclude_population'], 'paid_audience': self.advertiser_strategy['paid_audience'], 'is_open': self.advertiser_strategy['is_open'], 'no_age_break': self.advertiser_strategy['no_age_break'], 'no_gender_break': self.advertiser_strategy['no_gender_break'], 'no_area_break': self.advertiser_strategy['no_area_break'], 'behavior_interest': self.advertiser_strategy['behavior_interest']} # 3、从请求的信息中更新计划层级信息 if len(self.group_info) > 0: for key, value in self.group_info.items(): basic_group_info.update({key: value}) self.res_data['group_list'] = [] group_cnt = 1 for video in self.video: single_group_info = {'group_uuid': str(uuid.uuid4())} single_group_info.update(basic_group_info) single_group_info['unit_name'] = self.group_info['unit_name'] + '-' + str(group_cnt) # 组信息写入数据表中 single_group_info_to_db = single_group_info.copy() single_group_info_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid single_group_info_to_db['account_id'] = self.account_id single_group_info_to_db['campaign_id'] = self.campaign_id single_group_info_to_db['create_time'] = datetime.datetime.now() single_group_info_to_db['operation_type'] = self.operation_type df = pd.DataFrame.from_dict(single_group_info_to_db, orient='index').T engine = create_engine(db_con_str, connect_args={'charset': 'utf8'}) df.to_sql(name="ctop_ai_kuaishou_unit_level_operation_record", con=engine, if_exists='append', index=False) single_group_info['creative_list'] = [] group_cnt += 1 creative_cnt = 1 for image in video['imageList']: single_creative_info = { 'creative_uuid': str(uuid.uuid4()), 'is_sticky': 0, 'creative_name': self.creative_info['creative_name'] + '_' + str(creative_cnt), 'photo_id': video['photo_id'], 'image_md5': image, # TODO 需要和蒙蒙确认字段名称 'image_tokens': self.creative_info.get('image_tokens'), 'action_bar_text': self.creative_info['action_bar_text'], 'description': self.creative_info['description'], 'short_slogan': self.creative_info.get('short_slogan'), 'sticker_title': self.creative_info.get('sticker_title'), 'overlay_type': self.creative_info.get('overlay_type'), 'expose_tag': self.creative_info.get('expose_tag'), 'new_expose_tag': self.creative_info.get('new_expose_tag'), 'site_id': self.creative_info.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.creative_info.get('creative_category'), 'creative_tag': self.creative_info.get('creative_tag')} single_group_info['creative_list'].append(single_creative_info) # 创意层级写入数据表中 single_creative_info_to_db = single_creative_info.copy() single_creative_info_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid single_creative_info_to_db['account_id'] = self.account_id single_creative_info_to_db['campaign_id'] = self.campaign_id single_creative_info_to_db['create_time'] = datetime.datetime.now() single_creative_info_to_db['operation_type'] = self.operation_type df = pd.DataFrame.from_dict(single_creative_info_to_db, orient='index').T engine = create_engine(db_con_str, connect_args={'charset': 'utf8'}) df.to_sql(name="ctop_ai_kuaishou_creative_level_operation_record", con=engine, if_exists='append', index=False) creative_cnt += 1 # 组和创意信息添加到最终返回数据 group_list 中 self.res_data['group_list'].append(single_group_info) self.res_data['account_id'] = self.account_id self.res_data['campaign_id'] = self.campaign_id # TODO 修改操作 class ParseModifyRequest(object): def __init__(self): pass # TODO 关停操作 class ParseShutDownRequest(object): def __init__(self): pass