ai_strategy_request_func.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. import datetime
  2. import json
  3. import traceback
  4. import uuid
  5. from logging.handlers import TimedRotatingFileHandler
  6. import pandas as pd
  7. import pymysql
  8. import requests
  9. from utils.BaseClass import *
  10. from utils.DataBaseConfig import *
  11. from utils.LogConfig import *
  12. from utils.UrlConfig import *
  13. log_handler = TimedRotatingFileHandler("logs/ai_strategy_request.log",
  14. when="midnight", backupCount=100)
  15. log_handler.setFormatter(log_formatter)
  16. logger = logging.getLogger('ai_strategy_request_logger')
  17. logger.addHandler(log_handler)
  18. logger.setLevel(logging.DEBUG)
  19. print('id of ai_strategy_request_logger %s' % id(logger))
  20. def ai_strategy_request_parse(data):
  21. """
  22. 发送创建组和创意的请求
  23. :param data:
  24. :return:
  25. """
  26. print(data)
  27. if data["operation_type"] == 1:
  28. inst = ParseAddCampaignOrAddGroupRequest(data)
  29. # 1 获取客户策略信息
  30. inst.get_advertiser_strategy_info()
  31. # 2 写入智能策略信息
  32. inst.write_intelligence_strategy_table()
  33. # 3 判断 campaign_id 是否为空,为空则发送创建计划的请求
  34. if inst.campaign_id == "" or inst.campaign_id is None:
  35. if inst.add_campaign() == -1:
  36. return {'code': -2, 'message': '广告计划创建失败!'}
  37. # 4 unit_type "4-自定义" or "7-程序化创意2.0" ,调用对应的拼装参数函数
  38. if data['group_info'].get('unit_type', 4) == 4:
  39. inst.assemble_group_and_creative_params()
  40. if data['group_info'].get('unit_type', 4) == 7:
  41. inst.assemble_group_and_programme_creative_params()
  42. # 5 发送的请求信息更新到数据库表
  43. inst.update_intelligence_strategy_table(request_content=inst.res_data, message=None)
  44. # 6 发送创建组和创意的请求
  45. request = requests.post(create_group_and_creative_url,
  46. headers=headers,
  47. data=json.JSONEncoder().encode(inst.res_data))
  48. response_data = json.loads(request.text)
  49. # 7 接受的返回信息更新到数据库表
  50. inst.update_intelligence_strategy_table(message=response_data)
  51. # 8 写入日志信息
  52. logger.info("策略uuid = %s 的请求返回信息:%s" % (inst.ai_strategy_uuid, response_data))
  53. return {'code': 0, 'message': response_data}
  54. else:
  55. return {'code': -1, 'message': '暂时不支持非新增的操作请求!'}
  56. # 该类解析的是 手动请求的新增广告计划或者新增广告组的数据
  57. class ParseAddCampaignOrAddGroupRequest(object):
  58. def __init__(self, request_data):
  59. self.ai_strategy_uuid = str(uuid.uuid4())
  60. self.request_data = request_data
  61. self.video = self.request_data['video']['data']
  62. self.account_id = self.request_data['account_id']
  63. self.campaign_info = self.request_data['campaign_info']
  64. self.campaign_id = self.request_data['campaign_info'].get('campaign_id', None)
  65. self.group_info = self.request_data.get('group_info', None)
  66. self.creative_info = self.request_data.get('creative_info',None)
  67. self.operation_type = self.request_data['operation_type']
  68. self.advertiser_strategy_id = None
  69. self.advertiser_strategy = {}
  70. self.res_data = {}
  71. def get_advertiser_strategy_info(self):
  72. """
  73. 获取指定账户下客户的策略信息
  74. 为后续的写入库表,校验一致性做准备
  75. :return:
  76. """
  77. sql = """
  78. select *
  79. from ctop_ai_kuaishou_advertiser_strategy
  80. where account_id = %d
  81. and status = 1
  82. limit 1
  83. """ % self.account_id
  84. advertiser_strategy_df = pd.read_sql(sql, engine)
  85. self.advertiser_strategy_id = int(advertiser_strategy_df['id'].values[0])
  86. self.advertiser_strategy = advertiser_strategy_df.T.to_dict()[0]
  87. def write_intelligence_strategy_table(self):
  88. """
  89. 请求信息写入 ctop_ai_kuaishou_intelligence_strategy 表中
  90. :return:
  91. """
  92. intelligence_strategy_dict = \
  93. {
  94. 'ai_strategy_uuid': self.ai_strategy_uuid,
  95. 'advertiser_strategy_id': self.advertiser_strategy_id,
  96. 'account_id': self.account_id,
  97. 'ai_strategy_receive_content': str(self.request_data),
  98. 'ai_strategy_remark': self.request_data['ai_strategy_remark'],
  99. 'create_time': datetime.datetime.now()
  100. }
  101. df = pd.DataFrame.from_dict(intelligence_strategy_dict, orient='index').T
  102. print(df.dtypes)
  103. print("$$$$$$$$$$$$$")
  104. df.to_sql(name="ctop_ai_kuaishou_intelligence_strategy", con=engine, if_exists='append', index=False)
  105. print("^^^^^^^^^^^^^^^^^^^^")
  106. def update_intelligence_strategy_table(self, request_content=None, message=None):
  107. """
  108. 更新 intelligence_strategy_table
  109. :return:
  110. """
  111. db_con = pymysql.connect(host=host,
  112. port=port,
  113. user=user,
  114. password=passwd,
  115. database=db,
  116. charset=charset)
  117. cursor = db_con.cursor()
  118. if request_content:
  119. cursor.execute("""UPDATE ctop_ai_kuaishou_intelligence_strategy
  120. SET ai_strategy_request_content= %s
  121. WHERE ai_strategy_uuid = %s""", (str(request_content), self.ai_strategy_uuid))
  122. if message:
  123. cursor.execute("""UPDATE ctop_ai_kuaishou_intelligence_strategy
  124. SET message = %s
  125. WHERE ai_strategy_uuid = %s""", (str(message), self.ai_strategy_uuid))
  126. db_con.commit()
  127. db_con.close()
  128. def add_campaign(self):
  129. """
  130. 新增广告计划, 创建成功之后写入计划层级操作表中
  131. :return:
  132. """
  133. create_campaign_req_data = \
  134. {'account_id': self.account_id,
  135. 'campaign_name': self.campaign_info['campaign_name'],
  136. 'type': self.advertiser_strategy['campaign_type']}
  137. request = requests.post(url=create_campaign_url,
  138. headers=headers,
  139. data=json.JSONEncoder().encode(create_campaign_req_data))
  140. res_data = json.loads(request.text)
  141. # res_data = {
  142. # "code": 0,
  143. # "data": {
  144. # "account_id": 23212,
  145. # "campaign_id": 30956133,
  146. # "campaign_create_time": "2021-01-13 13:50:16"
  147. # },
  148. # "message": "SUCCESS"}
  149. campaign_info_to_db = {
  150. 'campaign_uuid': str(uuid.uuid4()),
  151. 'account_id': self.account_id,
  152. 'ai_strategy_uuid': self.ai_strategy_uuid,
  153. 'campaign_name': self.campaign_info['campaign_name'],
  154. 'campaign_type': self.advertiser_strategy['campaign_type'],
  155. 'operation_type': self.operation_type,
  156. 'create_time': datetime.datetime.now()
  157. }
  158. res = 0
  159. if res_data['code'] == 0:
  160. self.campaign_id = res_data['data']['campaign_id']
  161. campaign_info_to_db['campaign_id'] = self.campaign_id
  162. campaign_info_to_db['campaign_create_time'] = res_data['data']['campaign_create_time']
  163. campaign_info_to_db['status'] = res_data['code']
  164. campaign_info_to_db['message'] = res_data['message']
  165. logger.info("广告计划创建成功,campaign_id = %s, ai_strategy_uuid = %s" %
  166. (self.campaign_id, self.ai_strategy_uuid))
  167. else:
  168. campaign_info_to_db['message'] = res_data['message']
  169. campaign_info_to_db['status'] = res_data['code']
  170. logger.error("广告计划创建失败:%s, ai_strategy_uuid = %s" % (res_data['message'], self.ai_strategy_uuid))
  171. res = -1
  172. # 写入计划层级的操作表
  173. print("%%%%%%%%%%%%%%%%%%%%%%%%%%%")
  174. df = pd.DataFrame.from_dict(campaign_info_to_db, orient='index').T
  175. print(df.dtypes)
  176. df.to_sql(name="ctop_ai_kuaishou_campaign_level_operation_record",
  177. con=engine,
  178. if_exists='append',
  179. index=False)
  180. print("^^^^^^^^^^^^^^^^^^^^^^^^")
  181. return res
  182. def get_group_params(self):
  183. group_params = self.advertiser_strategy.copy()
  184. # 1 从客户策略表中,剔除掉不是组层级的参数(客户基本信息、计划层级信息、创意层级信息)
  185. drop_cols = ['id', 'account_id', 'status', 'campaign_type', 'campaign_name',
  186. 'creative_name', 'action_bar_text', 'description', 'short_slogan',
  187. 'sticker_title', 'overlay_type', 'expose_tag', 'new_expose_tag', 'site_id',
  188. 'click_track_url', 'impression_url', 'ad_photo_played_t3s_url', 'actionbar_click_url',
  189. 'creative_category', 'creative_tag', 'image_cnt',
  190. 'create_time', 'effective_time', 'expiry_time', 'timer_task_status']
  191. for col in drop_cols:
  192. if col in group_params.keys():
  193. del group_params[col]
  194. # 2 从请求的信息中更新组层级信息, 如组的名称、测试定向、测试出价等, update客户策略信息
  195. if (self.group_info is not None) and (len(self.group_info) > 0):
  196. for key, value in self.group_info.items():
  197. group_params.update({key: value})
  198. # 3 拼装json的组参数
  199. group_params_to_request = group_params.copy()
  200. # 3-1 拼接发送请求json时, 以下字段需要转为 list 类型
  201. cols_to_list = ['app_store', 'scene_id', 'region', 'district_ids', 'ages_range', 'device_brand',
  202. 'device_price', 'business_interest', 'fans_star', 'interest_video', 'app_interest',
  203. 'app_ids', 'population', 'exclude_population', 'paid_audience', 'behavior_interest']
  204. for col in cols_to_list:
  205. group_params_to_request[col] = eval(group_params_to_request[col]) \
  206. if ((group_params_to_request[col] is not None) and (group_params_to_request[col] != '')) else None
  207. # 3-2 发送请求,需要将 group_name 改为 unit_name
  208. group_params_to_request['unit_name'] = group_params_to_request.pop('group_name')
  209. # 4 写入数据库的组参数
  210. group_params_to_db = group_params.copy()
  211. group_params_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid
  212. group_params_to_db['account_id'] = self.account_id
  213. group_params_to_db['campaign_id'] = self.campaign_id
  214. group_params_to_db['operation_type'] = self.operation_type
  215. group_params_to_db['status'] = 1
  216. group_params_to_db['message'] = None
  217. return group_params_to_request, group_params_to_db
  218. def get_creative_params(self):
  219. # 1 从客户策略表中获取 创意层级基本信息
  220. creative_cols = ['creative_name', 'action_bar_text', 'description', 'short_slogan',
  221. 'sticker_title', 'overlay_type', 'expose_tag', 'new_expose_tag', 'site_id',
  222. 'click_track_url', 'impression_url', 'ad_photo_played_t3s_url', 'actionbar_click_url',
  223. 'creative_category', 'creative_tag']
  224. creative_params = {}
  225. for col in creative_cols:
  226. creative_params[col] = self.advertiser_strategy.get(col)
  227. # 2 从请求的信息中更新创意层级的信息,如广告语
  228. if (self.creative_info is not None) and (len(self.creative_info) > 0):
  229. for key, value in self.creative_info.items():
  230. creative_params.update({key: value})
  231. # 3 拼装json的 创意参数
  232. creative_params_to_request = creative_params.copy()
  233. # 3-1 拼接发送请求json时, 以下字段需要转为 list 类型
  234. cols_to_list = ['creative_tag']
  235. for col in cols_to_list:
  236. creative_params_to_request[col] = eval(creative_params_to_request[col]) \
  237. if ((creative_params_to_request[col] is not None) and (creative_params_to_request[col] != '')) else None
  238. # 4 写入数据库的创意参数
  239. creative_params_to_db = creative_params.copy()
  240. creative_params_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid
  241. creative_params_to_db['account_id'] = self.account_id
  242. creative_params_to_db['campaign_id'] = self.campaign_id
  243. creative_params_to_db['operation_type'] = self.operation_type
  244. creative_params_to_db['status'] = 1
  245. creative_params_to_db['message'] = None
  246. return creative_params_to_request, creative_params_to_db
  247. def get_programme_creative_params(self):
  248. # 1 从客户策略表中获取 创意层级基本信息
  249. creative_cols = ['creative_name', 'action_bar_text', 'description', 'site_id',
  250. 'click_track_url', 'actionbar_click_url',
  251. 'creative_category', 'creative_tag']
  252. creative_params = {}
  253. for col in creative_cols:
  254. creative_params[col] = self.advertiser_strategy.get(col)
  255. # 2 从请求的信息中更新创意层级的信息,如广告语,创意名称等
  256. if (self.creative_info is not None) and (len(self.creative_info) > 0):
  257. for key, value in self.creative_info.items():
  258. creative_params.update({key: value})
  259. # 3 程序化创意部分字段发生改变,需要重命名
  260. # creative_name --> package_name(程序化创意名称)
  261. # action_bar_text --> action_bar(行动号召按钮)
  262. # description --> captions(作品广告语) string[]
  263. # click_track_url --> click_url(点击监测链接)
  264. creative_params['package_name'] = creative_params.pop('creative_name')
  265. creative_params['action_bar'] = creative_params.pop('action_bar_text')
  266. description = creative_params.pop('description')
  267. creative_params['captions'] = str([description])
  268. creative_params['click_url'] = creative_params.pop('click_track_url')
  269. # 4 拼装json的 创意参数
  270. creative_params_to_request = creative_params.copy()
  271. # 4-1 拼接发送请求json时, 以下字段需要转为 list 类型
  272. cols_to_list = ['creative_tag', 'captions']
  273. for col in cols_to_list:
  274. creative_params_to_request[col] = eval(creative_params_to_request[col]) \
  275. if creative_params_to_request[col] is not None else None
  276. # 5 写入数据库的创意参数
  277. creative_params_to_db = creative_params.copy()
  278. creative_params_to_db['ai_strategy_uuid'] = self.ai_strategy_uuid
  279. creative_params_to_db['account_id'] = self.account_id
  280. creative_params_to_db['campaign_id'] = self.campaign_id
  281. creative_params_to_db['operation_type'] = self.operation_type
  282. creative_params_to_db['status'] = 1
  283. creative_params_to_db['message'] = None
  284. return creative_params_to_request, creative_params_to_db
  285. def assemble_group_and_creative_params(self):
  286. """
  287. 拼接组和创意层级参数
  288. 写入数据库
  289. :return:
  290. """
  291. # 获取组和创意的基本参数
  292. group_params_to_request, group_params_to_db = self.get_group_params()
  293. creative_params_to_request, creative_params_to_db = self.get_creative_params()
  294. self.res_data['group_list'] = []
  295. group_cnt = 1
  296. for video in self.video:
  297. group_uuid = str(uuid.uuid4())
  298. group_name = group_params_to_db['group_name'] + '-' + str(group_cnt)
  299. # 写入数据表中组信息
  300. single_group_params_to_db = group_params_to_db.copy()
  301. single_group_params_to_db['group_uuid'] = group_uuid
  302. single_group_params_to_db['group_name'] = group_name
  303. single_group_params_to_db['create_time'] = datetime.datetime.now()
  304. df = pd.DataFrame.from_dict(single_group_params_to_db, orient='index').T
  305. df.to_sql(name="ctop_ai_kuaishou_unit_level_operation_record",
  306. con=engine,
  307. if_exists='append',
  308. index=False)
  309. # 拼装返回json的组信息
  310. single_group_params_to_request = group_params_to_request.copy()
  311. single_group_params_to_request['group_uuid'] = group_uuid
  312. single_group_params_to_request['unit_name'] = group_name
  313. single_group_params_to_request['creative_list'] = []
  314. group_cnt += 1
  315. # 拼装组下面创意的信息
  316. creative_cnt = 1
  317. for image_md5 in video['imageList'][: self.advertiser_strategy['image_cnt']]:
  318. creative_uuid = str(uuid.uuid4())
  319. creative_name = creative_params_to_db['creative_name'] + '_' + str(creative_cnt)
  320. single_creative_params_to_db = creative_params_to_db.copy()
  321. single_creative_params_to_db['creative_uuid'] = creative_uuid
  322. single_creative_params_to_db['creative_name'] = creative_name
  323. single_creative_params_to_db['photo_id'] = video['photo_id']
  324. single_creative_params_to_db['image_md5'] = image_md5
  325. single_creative_params_to_db['create_time'] = datetime.datetime.now()
  326. df = pd.DataFrame.from_dict(single_creative_params_to_db, orient='index').T
  327. df.to_sql(name="ctop_ai_kuaishou_creative_level_operation_record",
  328. con=engine,
  329. if_exists='append',
  330. index=False)
  331. single_creative_params_to_request = creative_params_to_request.copy()
  332. single_creative_params_to_request['creative_uuid'] = creative_uuid
  333. single_creative_params_to_request['creative_name'] = creative_name
  334. single_creative_params_to_request['photo_id'] = video['photo_id']
  335. single_creative_params_to_request['image_md5'] = image_md5
  336. # 单个创意信息加入到组里面的 creative_list 中
  337. single_group_params_to_request['creative_list'].append(single_creative_params_to_request)
  338. creative_cnt += 1
  339. # 组和创意信息添加到最终返回数据 group_list 中
  340. self.res_data['group_list'].append(single_group_params_to_request)
  341. self.res_data['account_id'] = self.account_id
  342. self.res_data['campaign_id'] = self.campaign_id
  343. def assemble_group_and_programme_creative_params(self):
  344. """
  345. 拼接组和程序化创意的参数
  346. 写入数据库
  347. :return:
  348. """
  349. # 获取组和创意的基本参数
  350. group_params_to_request, group_params_to_db = self.get_group_params()
  351. creative_params_to_request, creative_params_to_db = self.get_programme_creative_params()
  352. # 每5个视频一组,来拼接组层级 和 程序化创意 层级的参数
  353. self.res_data['group_list'] = []
  354. cnt = 1
  355. for i in range(0, len(self.video), 5):
  356. group_uuid = str(uuid.uuid4())
  357. group_name = group_params_to_db['group_name'] + '-' + str(cnt)
  358. # 写入数据表中组信息
  359. single_group_params_to_db = group_params_to_db.copy()
  360. single_group_params_to_db['group_uuid'] = group_uuid
  361. single_group_params_to_db['group_name'] = group_name
  362. single_group_params_to_db['create_time'] = datetime.datetime.now()
  363. df = pd.DataFrame.from_dict(single_group_params_to_db, orient='index').T
  364. df.to_sql(name="ctop_ai_kuaishou_unit_level_operation_record",
  365. con=engine,
  366. if_exists='append',
  367. index=False)
  368. # 拼装返回json的组信息
  369. single_group_params_to_request = group_params_to_request.copy()
  370. single_group_params_to_request['group_uuid'] = group_uuid
  371. single_group_params_to_request['unit_name'] = group_name
  372. single_group_params_to_request['creative_list'] = []
  373. single_group_params_to_request['programCreative'] = None
  374. # 拼装程序化创意的信息
  375. horizontal_photo_ids = []
  376. vertical_photo_ids = []
  377. cover_image_tokens = []
  378. if i+5 < len(self.video):
  379. for j in range(i, i+5, 1):
  380. if self.video[j]['material_type'] == 2:
  381. horizontal_photo_ids.append(self.video[j]['photo_id'])
  382. cover_image_tokens.append(self.video[j]['imageList'][0])
  383. if self.video[j]['material_type'] == 1:
  384. vertical_photo_ids.append(self.video[j]['photo_id'])
  385. cover_image_tokens.append(self.video[j]['imageList'][0])
  386. if len(cover_image_tokens) >= 5:
  387. cover_image_tokens = cover_image_tokens[:4]
  388. creative_uuid = str(uuid.uuid4())
  389. package_name = creative_params_to_db['package_name'] + '_' + str(cnt)
  390. single_creative_params_to_db = creative_params_to_db.copy()
  391. single_creative_params_to_db['creative_uuid'] = creative_uuid
  392. single_creative_params_to_db['package_name'] = package_name
  393. single_creative_params_to_db['horizontal_photo_ids'] = str(horizontal_photo_ids)
  394. single_creative_params_to_db['vertical_photo_ids'] = str(vertical_photo_ids)
  395. single_creative_params_to_db['cover_image_tokens'] = str(cover_image_tokens)
  396. single_creative_params_to_db['create_time'] = datetime.datetime.now()
  397. df = pd.DataFrame.from_dict(single_creative_params_to_db, orient='index').T
  398. df.to_sql(name="ctop_ai_kuaishou_program_creative_level_operation_record",
  399. con=engine,
  400. if_exists='append',
  401. index=False)
  402. single_creative_params_to_request = creative_params_to_request.copy()
  403. single_creative_params_to_request['creative_uuid'] = creative_uuid
  404. single_creative_params_to_request['package_name'] = package_name
  405. single_creative_params_to_request['horizontal_photo_ids'] = horizontal_photo_ids
  406. single_creative_params_to_request['vertical_photo_ids'] = vertical_photo_ids
  407. single_creative_params_to_request['image_md5s'] = cover_image_tokens
  408. else:
  409. # material_type=1 竖版
  410. # material_type=2 横版
  411. for j in range(i, len(self.video)):
  412. if self.video[j]['material_type'] == 2:
  413. horizontal_photo_ids.append(self.video[j]['photo_id'])
  414. cover_image_tokens.append(self.video[j]['imageList'][0])
  415. if self.video[j]['material_type'] == 1:
  416. vertical_photo_ids.append(self.video[j]['photo_id'])
  417. cover_image_tokens.append(self.video[j]['imageList'][0])
  418. if len(cover_image_tokens) >= 5:
  419. cover_image_tokens = cover_image_tokens[:4]
  420. creative_uuid = str(uuid.uuid4())
  421. package_name = creative_params_to_db['package_name'] + '_' + str(cnt)
  422. single_creative_params_to_db = creative_params_to_db.copy()
  423. single_creative_params_to_db['creative_uuid'] = creative_uuid
  424. single_creative_params_to_db['package_name'] = package_name
  425. single_creative_params_to_db['horizontal_photo_ids'] = str(horizontal_photo_ids)
  426. single_creative_params_to_db['vertical_photo_ids'] = str(vertical_photo_ids)
  427. single_creative_params_to_db['cover_image_tokens'] = str(cover_image_tokens)
  428. single_creative_params_to_db['create_time'] = datetime.datetime.now()
  429. df = pd.DataFrame.from_dict(single_creative_params_to_db, orient='index').T
  430. df.to_sql(name="ctop_ai_kuaishou_program_creative_level_operation_record",
  431. con=engine,
  432. if_exists='append',
  433. index=False)
  434. single_creative_params_to_request = creative_params_to_request.copy()
  435. single_creative_params_to_request['creative_uuid'] = creative_uuid
  436. single_creative_params_to_request['package_name'] = package_name
  437. single_creative_params_to_request['horizontal_photo_ids'] = horizontal_photo_ids
  438. single_creative_params_to_request['vertical_photo_ids'] = vertical_photo_ids
  439. single_creative_params_to_request['image_md5s'] = cover_image_tokens
  440. single_group_params_to_request['programCreative'] = single_creative_params_to_request
  441. cnt += 1
  442. self.res_data['group_list'].append(single_group_params_to_request)
  443. self.res_data['account_id'] = self.account_id
  444. self.res_data['campaign_id'] = self.campaign_id
  445. # TODO 修改操作
  446. class ParseModifyRequest(object):
  447. def __init__(self):
  448. pass
  449. # TODO 关停操作
  450. class ParseShutDownRequest(object):
  451. def __init__(self):
  452. pass