ai_time_task_creative_handler.py 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. import pandas as pd
  2. from utils.UrlConfig import *
  3. import json
  4. import logging
  5. import traceback
  6. import random
  7. import tornado.web
  8. from concurrent_log import ConcurrentTimedRotatingFileHandler
  9. from utils.ConstantConfig import *
  10. from utils.DataBaseConfig import *
  11. from utils.CommonFunction import get_history_video_info, get_new_video_info, get_missing_video_info, \
  12. get_top_video_info, get_campaign_and_group_name_rule, get_app_detail, get_request_data, \
  13. refresh_video, get_app_list
  14. from ai_strategy_request_func import ai_strategy_request_parse
  15. log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%m/%d/%Y %I:%M:%S %p')
  16. log_handler = ConcurrentTimedRotatingFileHandler("logs/ai_auto_create.log", when="midnight", backupCount=100)
  17. log_handler.setFormatter(log_formatter)
  18. logger = logging.getLogger('ai_time_task_creative_logger')
  19. logger.addHandler(log_handler)
  20. logger.setLevel(logging.DEBUG)
  21. print('id of ai_time_task_creative_logger %s' % id(logger))
  22. logger.info("ai_time_task_creative_server started!")
  23. class AiHistoricalMissingMaterial(tornado.web.RequestHandler):
  24. """
  25. 补充历史遗漏素材(关联创意个数为0个素材)
  26. """
  27. def post(self):
  28. data = self.request.body
  29. data = str(data, 'utf8')
  30. data = json.loads(data, encoding='utf8')
  31. logger.info("*************************************** NEW REQUEST ***************************************")
  32. account_id = data.get('account_id')
  33. campaign_id = data.get('campaign_id')
  34. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  35. (account_id, os.getpid(), os.getppid(), data))
  36. try:
  37. sql = """
  38. select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  39. where account_id=%s order by create_time desc limit 1
  40. """ % account_id
  41. df = pd.read_sql(sql, engine)
  42. if df['general_track'].values[0] == 0:
  43. app_id_array = eval(df['app_id_array'].values[0])
  44. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  45. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  46. app_dict = {}
  47. for app_info in app_list['data']:
  48. if app_info['appId'] in app_id_array:
  49. app_dict[app_info['appVersion']] = app_info
  50. video_list = get_missing_video_info(account_id=account_id,
  51. cnt=missing_video_cnt,
  52. url=get_missing_video_url,
  53. start_time=missing_video_start_time,
  54. end_time=missing_video_end_time)
  55. # 返回视频中有通用视频和特定视频,需要分开处理
  56. # "photo_name": "all",
  57. # "photo_name": "ksjytdrca-糖豆人冲啊",
  58. if video_list['code'] == 0:
  59. video_df = pd.DataFrame(video_list['data'])
  60. # 1-非通用视频的创建
  61. special_video_df = video_df[video_df.photo_name != 'all']
  62. for photo_name in special_video_df['photo_name'].unique():
  63. if photo_name in app_dict.keys():
  64. campaign_id = None
  65. app_id = app_dict[photo_name].get('appId', 'error')
  66. app_version = app_dict[photo_name].get('appVersion', 'error')
  67. track_url = app_dict[photo_name].get('trackUrl', 'error')
  68. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  69. campaign_df = pd.read_sql(sql, engine)
  70. for row in campaign_df.itertuples():
  71. if (app_version + '--优选广告位-' + '遗漏素材') == getattr(row, 'campaign_name'):
  72. campaign_id = getattr(row, 'campaign_id')
  73. break
  74. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  75. app_id_video_list = []
  76. for k, v in app_id_video_df.T.to_dict().items():
  77. app_id_video_list.append(v)
  78. request_data = get_request_data(account_id=account_id,
  79. campaign_id=campaign_id,
  80. video_info=app_id_video_list,
  81. campaign_name=app_version + '--优选广告位-' + '遗漏素材',
  82. group_name=app_version + '-优选广告位-不限-自定义-' + '遗漏素材',
  83. ai_strategy_remark="补充遗漏素材",
  84. unit_type=4,
  85. app_id=app_id,
  86. click_track_url=track_url,
  87. creative_name=app_version)
  88. request = ai_strategy_request_parse(request_data)
  89. logger.info("account_id=%s, app_id=%s, 补充遗漏素材-特定视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  90. # 2-通用视频的创建,random.shuffle 选择 app_id
  91. general_video_df = video_df[video_df.photo_name == 'all']
  92. if not general_video_df.empty:
  93. general_video_cnt = len(general_video_df)
  94. app_version_list = list(app_dict)
  95. random.shuffle(app_version_list)
  96. video_cnt = 0
  97. for app_version in app_version_list[:general_video_cnt]:
  98. campaign_id = None
  99. app_id = app_dict[app_version].get('appId', 'error')
  100. track_url = app_dict[app_version].get('trackUrl', 'error')
  101. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  102. campaign_df = pd.read_sql(sql, engine)
  103. for row in campaign_df.itertuples():
  104. if (app_version + '--优选广告位-' + '遗漏素材') == getattr(row, 'campaign_name'):
  105. campaign_id = getattr(row, 'campaign_id')
  106. break
  107. single_video = [general_video_df.iloc[video_cnt, :].T.to_dict()]
  108. request_data = get_request_data(account_id=account_id,
  109. campaign_id=campaign_id,
  110. video_info=single_video,
  111. campaign_name=app_version + '--优选广告位-' + '遗漏素材',
  112. group_name=app_version + '-优选广告位-不限-自定义-' + '遗漏素材',
  113. ai_strategy_remark="补充遗漏素材",
  114. unit_type=4,
  115. app_id=app_id,
  116. click_track_url=track_url,
  117. creative_name=app_version)
  118. request = ai_strategy_request_parse(request_data)
  119. video_cnt += 1
  120. logger.info("account_id=%s, app_id=%s, 补充遗漏素材-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  121. else:
  122. logger.info("account_id=%s, 补充遗漏素材: 返回的视频中没有通用视频" % account_id)
  123. self.write(json.dumps({"message": "account_id=%s, 多应用的补充遗漏素材请求已走完!" % account_id}))
  124. self.flush()
  125. else:
  126. video_info = get_missing_video_info(account_id=account_id,
  127. cnt=missing_video_cnt,
  128. url=get_missing_video_url,
  129. start_time=missing_video_start_time,
  130. end_time=missing_video_end_time)
  131. if video_info['code'] != 0:
  132. logger.info("account_id = %s,补充历史遗漏素材,没有获取到视频,不发送ai策略请求!" % account_id)
  133. self.write(json.dumps({"account_id": account_id,
  134. "message": "补充历史遗漏素材,没有获取到视频,不发送ai策略请求!"}))
  135. self.flush()
  136. else:
  137. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  138. if (campaign_name is None) or (group_name is None):
  139. logger.info("没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!")
  140. self.write(json.dumps({"message": "没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  141. self.flush()
  142. else:
  143. request_data = get_request_data(account_id=account_id,
  144. campaign_id=campaign_id,
  145. video_info=video_info['data'],
  146. campaign_name=campaign_name,
  147. group_name=group_name,
  148. ai_strategy_remark="补充遗漏素材",
  149. name_replace="补充遗漏素材")
  150. request = ai_strategy_request_parse(request_data)
  151. logger.info("account_id = %s, 补充遗漏素材,ai策略的返回信息:%s" % (account_id, request))
  152. self.write(json.dumps(request))
  153. self.flush()
  154. except Exception:
  155. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  156. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  157. self.flush()
  158. class AiAutoCreative(tornado.web.RequestHandler):
  159. """
  160. 每5分钟,检查一次是否有上新素材,有的话,就自动创建
  161. """
  162. def post(self):
  163. data = self.request.body
  164. data = str(data, 'utf8')
  165. data = json.loads(data, encoding='utf8')
  166. logger.info("*************************************** NEW REQUEST ***************************************")
  167. account_id = data.get('account_id')
  168. campaign_id = data.get('campaign_id')
  169. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  170. (account_id, os.getpid(), os.getppid(), data))
  171. try:
  172. # 刷新快手视频信息
  173. refresh_video(account_id=account_id, url=refresh_video_url)
  174. sql = """
  175. select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  176. where account_id=%s order by create_time desc limit 1
  177. """ % account_id
  178. df = pd.read_sql(sql, engine)
  179. if df['general_track'].values[0] == 0:
  180. app_id_array = eval(df['app_id_array'].values[0])
  181. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  182. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  183. app_dict = {}
  184. for app_info in app_list['data']:
  185. if app_info['appId'] in app_id_array:
  186. app_dict[app_info['appVersion']] = app_info
  187. video_list = get_new_video_info(account_id=account_id,
  188. url=get_new_video_url)
  189. # 返回的视频中有通用视频和特定视频,需要分开处理
  190. # "photo_name": "all",
  191. # "photo_name": "ksjytdrca-糖豆人冲啊",
  192. if video_list['code'] == 0:
  193. video_df = pd.DataFrame(video_list['data'])
  194. # 1-特定视频的创建
  195. special_video_df = video_df[video_df.photo_name != 'all']
  196. for photo_name in special_video_df['photo_name'].unique():
  197. if photo_name in app_dict.keys():
  198. campaign_id = None
  199. app_id = app_dict[photo_name].get('appId', 'error')
  200. app_version = app_dict[photo_name].get('appVersion', 'error')
  201. track_url = app_dict[photo_name].get('trackUrl', 'error')
  202. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  203. campaign_df = pd.read_sql(sql, engine)
  204. for row in campaign_df.itertuples():
  205. if (app_version + '--优选广告位-' + '素材自动上新') == getattr(row, 'campaign_name'):
  206. campaign_id = getattr(row, 'campaign_id')
  207. break
  208. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  209. app_id_video_list = []
  210. for k, v in app_id_video_df.T.to_dict().items():
  211. app_id_video_list.append(v)
  212. request_data = get_request_data(account_id=account_id,
  213. campaign_id=campaign_id,
  214. video_info=app_id_video_list,
  215. campaign_name=app_version + '--优选广告位-' + '素材自动上新',
  216. group_name=app_version + '-优选广告位-不限-自定义-' + '素材自动上新',
  217. ai_strategy_remark="素材自动上新",
  218. unit_type=4,
  219. app_id=app_id,
  220. click_track_url=track_url,
  221. creative_name=app_version)
  222. request = ai_strategy_request_parse(request_data)
  223. logger.info("account_id=%s, app_id=%s, 素材自动上新-特定视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  224. # 2-通用视频的创建,random.shuffle 选择 app_id
  225. general_video_df = video_df[video_df.photo_name == 'all']
  226. if not general_video_df.empty:
  227. general_video_cnt = len(general_video_df)
  228. app_version_list = list(app_dict)
  229. random.shuffle(app_version_list)
  230. video_cnt = 0
  231. for app_version in app_version_list[:general_video_cnt]:
  232. campaign_id = None
  233. app_id = app_dict[app_version].get('appId', 'error')
  234. track_url = app_dict[app_version].get('trackUrl', 'error')
  235. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  236. campaign_df = pd.read_sql(sql, engine)
  237. for row in campaign_df.itertuples():
  238. if (app_version + '--优选广告位-' + '素材自动上新') == getattr(row, 'campaign_name'):
  239. campaign_id = getattr(row, 'campaign_id')
  240. break
  241. single_video = [general_video_df.iloc[video_cnt, :].T.to_dict()]
  242. request_data = get_request_data(account_id=account_id,
  243. campaign_id=campaign_id,
  244. video_info=single_video,
  245. campaign_name=app_version + '--优选广告位-' + '素材自动上新',
  246. group_name=app_version + '-优选广告位-不限-自定义-' + '素材自动上新',
  247. ai_strategy_remark="素材自动上新",
  248. unit_type=4,
  249. app_id=app_id,
  250. click_track_url=track_url,
  251. creative_name=app_version)
  252. request = ai_strategy_request_parse(request_data)
  253. video_cnt += 1
  254. logger.info("account_id=%s, app_id=%s, 素材自动上新-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  255. else:
  256. logger.info("account_id=%s, 素材自动上新: 返回的视频中没有通用视频" % account_id)
  257. else:
  258. logger.info("account_id=%s, 素材自动上新: 没有获取到视频" % account_id)
  259. self.write(json.dumps({"message": "account_id=%s, 多应用的素材自动上新已走完!" % account_id}))
  260. self.flush()
  261. else:
  262. start_time = (datetime.date.today()).strftime('%Y-%m-%d %H:%M:%S')
  263. end_time = (datetime.datetime.now()).strftime('%Y-%m-%d %H:%M:%S')
  264. # 1-1 获取当天计划中包含“自动上新”计划的,计划id
  265. sql = """
  266. select campaign_id, campaign_name from ctop_kuaishou_campaign
  267. where account_id = %s
  268. and put_create_time >= '%s'
  269. and put_create_time <= '%s'
  270. """ % (account_id, start_time, end_time)
  271. df = pd.read_sql(sql, engine)
  272. for row in df.itertuples():
  273. if '素材自动上新' in getattr(row, 'campaign_name'):
  274. campaign_id = getattr(row, 'campaign_id')
  275. break
  276. video_info = get_new_video_info(account_id=account_id,
  277. url=get_new_video_url)
  278. if video_info['code'] != 0:
  279. self.write(json.dumps({"account_id": account_id, "message": "素材自动上新没有获取到视频,不发送ai策略请求!"}))
  280. self.flush()
  281. else:
  282. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  283. if (campaign_name is None) or (group_name is None):
  284. logger.info("account_id = %s, 素材自动上新 没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"
  285. % account_id)
  286. self.write(json.dumps({"account_id": account_id,
  287. "message": "素材自动上新 没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  288. self.flush()
  289. else:
  290. request_data = get_request_data(account_id=account_id,
  291. campaign_id=campaign_id,
  292. video_info=video_info['data'],
  293. campaign_name=campaign_name,
  294. group_name=group_name,
  295. ai_strategy_remark="自动上新",
  296. name_replace="素材自动上新")
  297. request = ai_strategy_request_parse(request_data)
  298. logger.info("account_id = %s, 素材自动上新 ai策略的返回信息:%s" % (account_id, request))
  299. self.write(json.dumps(request))
  300. self.flush()
  301. except Exception:
  302. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  303. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  304. self.flush()
  305. class AiHighQualityMaterial(tornado.web.RequestHandler):
  306. """
  307. 补充历史高质量素材 -- 测试通过 在AD后台创建成功,检查AD信息和数据库表 没有问题
  308. """
  309. def post(self):
  310. data = self.request.body
  311. data = str(data, 'utf8')
  312. data = json.loads(data, encoding='utf8')
  313. logger.info("*************************************** NEW REQUEST ***************************************")
  314. account_id = data.get('account_id')
  315. campaign_id = data.get('campaign_id')
  316. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  317. (account_id, os.getpid(), os.getppid(), data))
  318. try:
  319. sql = """select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  320. where account_id=%s order by create_time desc limit 1
  321. """ % account_id
  322. df = pd.read_sql(sql, engine)
  323. if df['general_track'].values[0] == 0:
  324. app_id_array = eval(df['app_id_array'].values[0])
  325. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  326. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  327. app_dict = {}
  328. for app_info in app_list['data']:
  329. if app_info['appId'] in app_id_array:
  330. app_dict[app_info['appVersion']] = app_info
  331. video_list = get_top_video_info(account_id=account_id,
  332. cnt=high_quality_video_cnt,
  333. start_time=(datetime.datetime.now() +
  334. datetime.timedelta(days=-high_quality_video_days)).
  335. strftime("%Y-%m-%d %H:%M:%S"),
  336. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  337. strftime("%Y-%m-%d %H:%M:%S"),
  338. url=get_high_quality_video_url)
  339. # 单独处理返回的时候中,有通用视频,需要单独处理
  340. # "photo_name": "all",
  341. # "photo_name": "ksjytdrca-糖豆人冲啊",
  342. if video_list['code'] == 0:
  343. video_df = pd.DataFrame(video_list['data'])
  344. # 1-特定视频的创建
  345. special_video_df = video_df[video_df.photo_name != 'all']
  346. for photo_name in special_video_df['photo_name'].unique():
  347. if photo_name in app_dict.keys():
  348. campaign_id = None
  349. app_id = app_dict[photo_name].get('appId', 'error')
  350. app_version = app_dict[photo_name].get('appVersion', 'error')
  351. track_url = app_dict[photo_name].get('trackUrl', 'error')
  352. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  353. campaign_df = pd.read_sql(sql, engine)
  354. for row in campaign_df.itertuples():
  355. if (app_version + '--优选广告位-' + '高质量素材') == getattr(row, 'campaign_name'):
  356. campaign_id = getattr(row, 'campaign_id')
  357. break
  358. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  359. app_id_video_list = []
  360. for k, v in app_id_video_df.T.to_dict().items():
  361. app_id_video_list.append(v)
  362. request_data = get_request_data(account_id=account_id,
  363. campaign_id=campaign_id,
  364. video_info=app_id_video_list,
  365. campaign_name=app_version + '--优选广告位-' + '高质量素材',
  366. group_name=app_version + '-优选广告位-不限-自定义-' + '高质量素材',
  367. ai_strategy_remark="高质量素材复建",
  368. unit_type=4,
  369. app_id=app_id,
  370. click_track_url=track_url,
  371. creative_name=app_version)
  372. request = ai_strategy_request_parse(request_data)
  373. logger.info("account_id=%s, app_id=%s, 高质量素材复建-特定视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  374. # 2-通用视频的创建,random.shuffle 选择 app_id
  375. general_video_df = video_df[video_df.photo_name == 'all']
  376. if not general_video_df.empty:
  377. general_video_cnt = len(general_video_df)
  378. app_version_list = list(app_dict)
  379. random.shuffle(app_version_list)
  380. video_cnt = 0
  381. for app_version in app_version_list[:general_video_cnt]:
  382. campaign_id = None
  383. app_id = app_dict[app_version].get('appId', 'error')
  384. track_url = app_dict[app_version].get('trackUrl', 'error')
  385. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  386. campaign_df = pd.read_sql(sql, engine)
  387. for row in campaign_df.itertuples():
  388. if (app_version + '--优选广告位-' + '高质量素材') == getattr(row, 'campaign_name'):
  389. campaign_id = getattr(row, 'campaign_id')
  390. break
  391. single_video = [general_video_df.iloc[video_cnt, :].T.to_dict()]
  392. request_data = get_request_data(account_id=account_id,
  393. campaign_id=campaign_id,
  394. video_info=single_video,
  395. campaign_name=app_version + '--优选广告位-' + '高质量素材',
  396. group_name=app_version + '-优选广告位-不限-自定义-' + '高质量素材',
  397. ai_strategy_remark="高质量素材复建",
  398. unit_type=4,
  399. app_id=app_id,
  400. click_track_url=track_url,
  401. creative_name=app_version)
  402. request = ai_strategy_request_parse(request_data)
  403. video_cnt += 1
  404. logger.info("account_id=%s, app_id=%s, 高质量素材复建-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  405. else:
  406. logger.info("account_id=%s, 高质量素材复建: 返回的视频中没有通用视频" % account_id)
  407. else:
  408. logger.info("account_id=%s, 高质量素材复建: 没有获取到视频" % account_id)
  409. self.write(json.dumps({"message": "account_id=%s, 多应用的高质量素材复建请求已走完!" % account_id}))
  410. self.flush()
  411. else:
  412. video_info = get_top_video_info(account_id=account_id,
  413. cnt=high_quality_video_cnt,
  414. start_time=(datetime.datetime.now() +
  415. datetime.timedelta(days=-high_quality_video_days)).
  416. strftime("%Y-%m-%d %H:%M:%S"),
  417. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  418. strftime("%Y-%m-%d %H:%M:%S"),
  419. url=get_high_quality_video_url)
  420. if video_info['code'] != 0:
  421. logger.info("account_id = %s, 高质量素材复建,没有获取到视频,不发送ai策略请求!" % account_id)
  422. self.write(json.dumps({"account_id": account_id,
  423. "message": "高质量素材复建,没有获取到视频,不发送ai策略请求!"}))
  424. self.flush()
  425. else:
  426. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  427. if (campaign_name is None) or (group_name is None):
  428. logger.error("account_id = %s, 没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!" % account_id)
  429. self.write(json.dumps({"account_id": account_id,
  430. "message": "没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  431. self.flush()
  432. else:
  433. request_data = get_request_data(account_id=account_id,
  434. campaign_id=campaign_id,
  435. video_info=video_info['data'],
  436. campaign_name=campaign_name,
  437. group_name=group_name,
  438. ai_strategy_remark="高质量素材复建",
  439. name_replace="高质量素材")
  440. request = ai_strategy_request_parse(request_data)
  441. logger.info("account_id = %s, 高质量素材复建,ai策略的返回信息:%s" % (account_id, request))
  442. self.write(json.dumps(request))
  443. self.flush()
  444. except Exception:
  445. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  446. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  447. self.flush()
  448. class AiUpCreativeByHour(tornado.web.RequestHandler):
  449. """
  450. 1点到20点,每小时执行一次,检查当前时点创意个数是否达到hour*100
  451. 没有达到则按照当前时点值,补充不同类型的视频
  452. """
  453. def post(self):
  454. data = self.request.body
  455. data = str(data, 'utf8')
  456. data = json.loads(data, encoding='utf8')
  457. account_id = data.get('account_id')
  458. campaign_id = data.get('campaign_id')
  459. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  460. (account_id, os.getpid(), os.getppid(), data))
  461. try:
  462. # 1 从客户策略表中获取该账户下 每个素材搭配的封面个数, 来计算需要补充的素材个数
  463. sql = """select image_cnt from ctop_ai_kuaishou_advertiser_strategy
  464. where account_id = %s
  465. limit 1""" % account_id
  466. df = pd.read_sql(sql, engine)
  467. image_cnt = int(df['image_cnt'].values[0])
  468. # 2、获取从0点到now()为止,该账户下已有的创意个数 M
  469. sql = """select count(1) creative_cnt from ctop_kuaishou_creative
  470. where account_id = %s
  471. and creative_id is not NULL
  472. and creative_create_time <= '%s'
  473. and creative_create_time >= '%s'""" % (account_id,
  474. (datetime.datetime.now()).strftime('%Y-%m-%d %H:%M:%S'),
  475. (datetime.datetime.now()).strftime('%Y-%m-%d'))
  476. df = pd.read_sql(sql, engine)
  477. exist_creative_cnt = int(df['creative_cnt'].values[0])
  478. now_hour = datetime.datetime.now().hour
  479. now = datetime.datetime.now()
  480. should_creative_cnt = now_hour * 100
  481. # 3、计算需要补充的创意个数和视频个数,并按当前小时值,补充不同类似的视频
  482. if exist_creative_cnt < should_creative_cnt:
  483. need_video_cnt = (should_creative_cnt - exist_creative_cnt) // image_cnt
  484. logger.info("account_id = %s, 按小时需要补充的视频数量 = %s" % (account_id, need_video_cnt))
  485. if now_hour % 5 == 0:
  486. # campaign_group_name_place 用于广告计划和广告组名称的标识
  487. campaign_group_name_place = "高质量素材"
  488. video_list = get_top_video_info(account_id=account_id,
  489. url=get_high_quality_video_url,
  490. start_time=(now + datetime.timedelta(days=-high_quality_video_days)).
  491. strftime("%Y-%m-%d %H:%M:%S"),
  492. end_time=(now + datetime.timedelta(days=-1)).
  493. strftime("%Y-%m-%d %H:%M:%S"),
  494. cnt=need_video_cnt,
  495. app_version=None)
  496. elif (now_hour % 5 == 1) or (now_hour % 5 == 2):
  497. campaign_group_name_place = "历史素材打捞"
  498. video_list = get_history_video_info(account_id=account_id,
  499. url=get_history_video_url,
  500. start_time=history_video_start_time,
  501. end_time=history_video_end_time,
  502. video_cnt=need_video_cnt,
  503. related_creative_max_cnt=related_creative_max_cnt)
  504. else:
  505. campaign_group_name_place = "遗漏素材"
  506. video_list = get_missing_video_info(account_id=account_id,
  507. cnt=need_video_cnt,
  508. url=get_missing_video_url,
  509. start_time=missing_video_start_time,
  510. end_time=missing_video_end_time)
  511. if video_list['code'] == 0:
  512. # 根据获取到的视频进行创建
  513. sql = """select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  514. where account_id=%s order by create_time desc limit 1""" % account_id
  515. df = pd.read_sql(sql, engine)
  516. if df['general_track'].values[0] == 0:
  517. app_id_array = eval(df['app_id_array'].values[0])
  518. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  519. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  520. app_dict = {}
  521. for app_info in app_list['data']:
  522. if app_info['appId'] in app_id_array:
  523. app_dict[app_info['appVersion']] = app_info
  524. # 单独处理返回的时候中,有通用视频,需要单独处理
  525. # "photo_name": "all",
  526. # "photo_name": "ksjytdrca-糖豆人冲啊",
  527. video_df = pd.DataFrame(video_list['data'])
  528. # 1-特定视频的创建
  529. special_video_df = video_df[video_df.photo_name != 'all']
  530. for photo_name in special_video_df['photo_name'].unique():
  531. if photo_name in app_dict.keys():
  532. campaign_id = None
  533. app_id = app_dict[photo_name].get('appId', 'error')
  534. app_version = app_dict[photo_name].get('appVersion', 'error')
  535. track_url = app_dict[photo_name].get('trackUrl', 'error')
  536. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  537. campaign_df = pd.read_sql(sql, engine)
  538. for row in campaign_df.itertuples():
  539. if (app_version + '--优选广告位-' + campaign_group_name_place) == getattr(row, 'campaign_name'):
  540. campaign_id = getattr(row, 'campaign_id')
  541. break
  542. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  543. app_id_video_list = []
  544. for k, v in app_id_video_df.T.to_dict().items():
  545. app_id_video_list.append(v)
  546. request_data = get_request_data(account_id=account_id,
  547. campaign_id=campaign_id,
  548. video_info=app_id_video_list,
  549. campaign_name=app_version+'--优选广告位-'+campaign_group_name_place,
  550. group_name=app_version+'-优选广告位-不限-自定义-'+campaign_group_name_place,
  551. ai_strategy_remark="按小时补充创意-"+campaign_group_name_place,
  552. unit_type=4,
  553. app_id=app_id,
  554. click_track_url=track_url,
  555. creative_name=app_version)
  556. request = ai_strategy_request_parse(request_data)
  557. logger.info("account_id=%s, app_id=%s, %s补充创意-特定视频,ai策略的返回信息:%s" %
  558. (account_id, app_id, campaign_group_name_place, request))
  559. # 2-通用视频的创建,random.shuffle 选择 app_id
  560. general_video_df = video_df[video_df.photo_name == 'all']
  561. if not general_video_df.empty:
  562. # 每 batch_num 一组 随机选择一个app_id 进行创建
  563. batch_num = 10
  564. general_video_cnt = len(general_video_df)
  565. app_version_list = list(app_dict)
  566. random.shuffle(app_version_list)
  567. need_app_id_cnt = general_video_cnt // batch_num + 1
  568. video_cnt = 0
  569. for app_version in app_version_list[:need_app_id_cnt]:
  570. campaign_id = None
  571. app_id = app_dict[app_version].get('appId', 'error')
  572. track_url = app_dict[app_version].get('trackUrl', 'error')
  573. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  574. campaign_df = pd.read_sql(sql, engine)
  575. for row in campaign_df.itertuples():
  576. if (app_version + '--优选广告位-' + campaign_group_name_place) == getattr(row, 'campaign_name'):
  577. campaign_id = getattr(row, 'campaign_id')
  578. break
  579. batch_general_video_list = []
  580. for k, v in general_video_df.iloc[video_cnt: video_cnt+batch_num, :].T.to_dict().items():
  581. batch_general_video_list.append(v)
  582. request_data = get_request_data(account_id=account_id,
  583. campaign_id=campaign_id,
  584. video_info=batch_general_video_list,
  585. campaign_name=app_version + '--优选广告位-' + campaign_group_name_place,
  586. group_name=app_version + '-优选广告位-不限-自定义-' + campaign_group_name_place,
  587. ai_strategy_remark="按小时补充创意-"+campaign_group_name_place,
  588. unit_type=4,
  589. app_id=app_id,
  590. click_track_url=track_url,
  591. creative_name=app_version)
  592. request = ai_strategy_request_parse(request_data)
  593. video_cnt += batch_num
  594. logger.info("account_id=%s, app_id=%s, %s补充创意-通用视频,ai策略的返回信息:%s" %
  595. (account_id, app_id, campaign_group_name_place, request))
  596. else:
  597. logger.info("account_id=%s, %s补充创意: 返回的视频中没有通用视频" % (account_id, campaign_group_name_place))
  598. self.write(json.dumps({"message": "account_id=%s, %s补充创意请求已走完!" % (account_id, campaign_group_name_place)}))
  599. self.flush()
  600. else:
  601. # 获取当天计划中包含“campaign_group_name_place”计划的,计划id
  602. sql = """select campaign_id, campaign_name from ctop_kuaishou_campaign
  603. where account_id = %s
  604. and put_create_time <= '%s'
  605. and put_create_time >= '%s' """ % (account_id,
  606. (datetime.datetime.now()).strftime('%Y-%m-%d %H:%M:%S'),
  607. (datetime.datetime.now()).strftime('%Y-%m-%d'))
  608. df = pd.read_sql(sql, engine)
  609. for row in df.itertuples():
  610. if campaign_group_name_place in getattr(row, 'campaign_name'):
  611. campaign_id = getattr(row, 'campaign_id')
  612. break
  613. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  614. if (campaign_name is None) or (group_name is None):
  615. logger.info("account_id = %s, 没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!" % account_id)
  616. self.write(json.dumps({"account_id": account_id,
  617. "message": "没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  618. self.flush()
  619. else:
  620. request_data = get_request_data(account_id=account_id,
  621. campaign_id=campaign_id,
  622. video_info=video_list['data'],
  623. campaign_name=campaign_name,
  624. group_name=group_name,
  625. ai_strategy_remark="按小时补充创意-"+campaign_group_name_place,
  626. name_replace=campaign_group_name_place)
  627. request = ai_strategy_request_parse(request_data)
  628. logger.info("account_id = %s, %s补充创意,ai策略的返回信息:%s" % (account_id, campaign_group_name_place, request))
  629. self.write(json.dumps(request))
  630. self.flush()
  631. else:
  632. logger.info("account_id=%s, 按小时补充创意: 没有成功获取到视频!" % account_id)
  633. self.write(json.dumps({"message": "account_id=%s, 按小时补充创意: 没有成功获取到视频!" % account_id}))
  634. self.flush()
  635. except Exception:
  636. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  637. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  638. self.flush()
  639. class AiProgramCreativeHighQualityMaterial(tornado.web.RequestHandler):
  640. """
  641. 使用历史跑量素材创建程序化创意
  642. 跑量素材150个(近14天的素材)
  643. 计划名称--跑量素材程序化
  644. timeTask: 每天上午10点执行 --(0 0 10 * * ?)
  645. ----------------------------------------
  646. 拼装参数和写入数据库时,需要修改名称(程序化与非程序化不一致):
  647. creative_name --> package_name(程序化创意名称)
  648. action_bar_text --> action_bar(行动号召按钮)
  649. description --> captions(作品广告语)
  650. click_track_url --> click_url
  651. 写入数据库时:
  652. image_md5s --> cover_image_tokens
  653. 程序化与非程序化的逻辑不一样:
  654. 需要5个视频4张封面一组,拼装程序化创意参数需要单独抽取一个方法出来
  655. 所有操作记录表中,添加status信息(已提交,成功,失败),和回调时的 message信息
  656. """
  657. def post(self):
  658. data = self.request.body
  659. data = str(data, 'utf8')
  660. data = json.loads(data, encoding='utf8')
  661. logger.info("*************************************** NEW REQUEST ***************************************")
  662. account_id = data.get('account_id')
  663. campaign_id = data.get('campaign_id')
  664. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  665. (account_id, os.getpid(), os.getppid(), data))
  666. try:
  667. sql = """select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  668. where account_id=%s order by create_time desc limit 1
  669. """ % account_id
  670. df = pd.read_sql(sql, engine)
  671. if df['general_track'].values[0] == 0:
  672. app_id_array = eval(df['app_id_array'].values[0])
  673. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  674. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  675. app_dict = {}
  676. for app_info in app_list['data']:
  677. if app_info['appId'] in app_id_array:
  678. app_dict[app_info['appVersion']] = app_info
  679. video_list = get_top_video_info(account_id=account_id,
  680. cnt=multi_app_id_programme_high_quality_video_cnt,
  681. start_time=(datetime.datetime.now() + datetime.timedelta(
  682. days=-high_quality_video_days)).strftime("%Y-%m-%d %H:%M:%S"),
  683. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  684. strftime("%Y-%m-%d %H:%M:%S"),
  685. url=get_high_quality_video_url)
  686. # 单独处理返回的时候中,有通用视频,需要单独处理
  687. # "photo_name": "all",
  688. # "photo_name": "ksjytdrca-糖豆人冲啊",
  689. if video_list['code'] == 0:
  690. video_df = pd.DataFrame(video_list['data'])
  691. # 1-特定视频的创建
  692. special_video_df = video_df[video_df.photo_name != 'all']
  693. for photo_name in special_video_df['photo_name'].unique():
  694. if photo_name in app_dict.keys():
  695. campaign_id = None
  696. app_id = app_dict[photo_name].get('appId', 'error')
  697. app_version = app_dict[photo_name].get('appVersion', 'error')
  698. track_url = app_dict[photo_name].get('trackUrl', 'error')
  699. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  700. campaign_df = pd.read_sql(sql, engine)
  701. for row in campaign_df.itertuples():
  702. if (app_version + '--优选广告位-' + '程序化高质量素材') == getattr(row, 'campaign_name'):
  703. campaign_id = getattr(row, 'campaign_id')
  704. break
  705. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  706. app_id_video_list = []
  707. for k, v in app_id_video_df.T.to_dict().items():
  708. app_id_video_list.append(v)
  709. request_data = get_request_data(account_id=account_id,
  710. campaign_id=campaign_id,
  711. video_info=app_id_video_list,
  712. campaign_name=app_version + '--优选广告位-' + '程序化高质量素材',
  713. group_name=app_version + '-优选广告位-不限-程序化-' + '高质量素材',
  714. ai_strategy_remark="程序化高质量素材",
  715. unit_type=7,
  716. app_id=app_id,
  717. click_track_url=track_url,
  718. creative_name=app_version)
  719. request = ai_strategy_request_parse(request_data)
  720. logger.info("account_id=%s, app_id=%s, 程序化高质量素材-特定视频,ai策略的返回信息:%s" %
  721. (account_id, app_id, request))
  722. # 2-通用视频的创建,random.shuffle 选择 app_id
  723. general_video_df = video_df[video_df.photo_name == 'all']
  724. general_video_list = []
  725. for k, v in general_video_df.T.to_dict().items():
  726. general_video_list.append(v)
  727. if general_video_list:
  728. app_version_list = list(app_dict)
  729. random.shuffle(app_version_list)
  730. # 每5个通用视频创建一个程序化广告组
  731. batch_num = 5
  732. app_id_cnt = 0
  733. for i in range(0, len(general_video_list), 5):
  734. if i + 5 < len(general_video_list):
  735. batch_general_video = general_video_list[i: i + batch_num]
  736. app_version = app_version_list[app_id_cnt]
  737. app_id = app_dict[app_version].get('appId', 'error')
  738. track_url = app_dict[app_version].get('trackUrl', 'error')
  739. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  740. campaign_df = pd.read_sql(sql, engine)
  741. for row in campaign_df.itertuples():
  742. if (app_version + '--优选广告位-' + '程序化高质量素材') == getattr(row, 'campaign_name'):
  743. campaign_id = getattr(row, 'campaign_id')
  744. break
  745. request_data = get_request_data(account_id=account_id,
  746. campaign_id=campaign_id,
  747. video_info=batch_general_video,
  748. campaign_name=app_version + '--优选广告位-' + '程序化高质量素材',
  749. group_name=app_version + '-优选广告位-不限-程序化-' + '高质量素材',
  750. ai_strategy_remark="程序化高质量素材",
  751. unit_type=7,
  752. app_id=app_id,
  753. click_track_url=track_url,
  754. creative_name=app_version)
  755. request = ai_strategy_request_parse(request_data)
  756. app_id_cnt += 1
  757. logger.info("account_id=%s, app_id=%s, 程序化高质量素材-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  758. else:
  759. batch_general_video = general_video_list[i: len(general_video_list)]
  760. app_version = app_version_list[app_id_cnt]
  761. app_id = app_dict[app_version].get('appId', 'error')
  762. track_url = app_dict[app_version].get('trackUrl', 'error')
  763. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  764. campaign_df = pd.read_sql(sql, engine)
  765. for row in campaign_df.itertuples():
  766. if (app_version + '--优选广告位-' + '程序化高质量素材') == getattr(row, 'campaign_name'):
  767. campaign_id = getattr(row, 'campaign_id')
  768. break
  769. request_data = get_request_data(account_id=account_id,
  770. campaign_id=campaign_id,
  771. video_info=batch_general_video,
  772. campaign_name=app_version + '--优选广告位-' + '程序化高质量素材',
  773. group_name=app_version + '-优选广告位-不限-程序化-' + '高质量素材',
  774. ai_strategy_remark="程序化高质量素材",
  775. unit_type=7,
  776. app_id=app_id,
  777. click_track_url=track_url,
  778. creative_name=app_version)
  779. request = ai_strategy_request_parse(request_data)
  780. logger.info("account_id=%s, app_id=%s, 程序化高质量素材-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  781. else:
  782. logger.info("account_id=%s, 程序化高质量素材: 返回的视频中没有通用视频" % account_id)
  783. self.write(json.dumps({"message": "account_id=%s, 程序化高质量素材请求已走完!" % account_id}))
  784. self.flush()
  785. else:
  786. video_info = get_top_video_info(account_id=account_id,
  787. cnt=programme_high_quality_video_cnt,
  788. start_time=(datetime.datetime.now() + datetime.timedelta(
  789. days=-high_quality_video_days)).strftime("%Y-%m-%d %H:%M:%S"),
  790. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  791. strftime("%Y-%m-%d %H:%M:%S"),
  792. url=get_high_quality_video_url)
  793. if video_info['code'] != 0:
  794. logger.info("account_id = %s, 程序化高质量素材,没有获取到视频,不发送ai策略请求!" % account_id)
  795. self.write(json.dumps({"account_id": account_id,
  796. "message": "没有获取到视频,不发送ai策略请求!"}))
  797. self.flush()
  798. else:
  799. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  800. if (campaign_name is None) or (group_name is None):
  801. logger.info("account_id = %s, 没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!" % account_id)
  802. self.write(json.dumps({"account_id": account_id,
  803. "message": "没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  804. self.flush()
  805. else:
  806. request_data = get_request_data(account_id=account_id,
  807. campaign_id=campaign_id,
  808. video_info=video_info['data'],
  809. campaign_name=campaign_name,
  810. group_name=group_name,
  811. ai_strategy_remark="程序化高质量素材",
  812. name_replace="程序化高质量素材",
  813. unit_type=7)
  814. request = ai_strategy_request_parse(request_data)
  815. logger.info("account_id = %s, 程序化高质量素材, ai策略的返回信息:%s" % (account_id, request))
  816. self.write(json.dumps(request))
  817. self.flush()
  818. except Exception:
  819. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  820. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  821. self.flush()
  822. class AiProgramCreativeNewMaterial(tornado.web.RequestHandler):
  823. """
  824. 使用N天内 创意数关联小于M个(如当天创意关联数小于10的,150个素材)的素材创建程序化创意
  825. 计划名称--新素材程序化
  826. timeTask: 每天上午10点执行 --(0 0 10 * * ?)
  827. """
  828. def post(self):
  829. data = self.request.body
  830. data = str(data, 'utf8')
  831. data = json.loads(data, encoding='utf8')
  832. logger.info("*************************************** NEW REQUEST ***************************************")
  833. account_id = data.get('account_id')
  834. campaign_id = data.get('campaign_id')
  835. logger.info("账户信息=%s, 当前进程=%s, 当前进程的主进程=%s, raw data from request is %s" %
  836. (account_id, os.getpid(), os.getppid(), data))
  837. try:
  838. sql = """select account_id, single_appid, app_id_array, general_track from ctop_ai_kuaishou_advertiser_strategy
  839. where account_id=%s order by create_time desc limit 1
  840. """ % account_id
  841. df = pd.read_sql(sql, engine)
  842. if df['general_track'].values[0] == 0:
  843. app_id_array = eval(df['app_id_array'].values[0])
  844. app_list = get_app_list(account_id=account_id, url=get_app_list_url)
  845. # app_dict key = ("appVersion": "ksjyrlyn-人类一脑涂地大败") , value = 完整的app_id信息
  846. app_dict = {}
  847. for app_info in app_list['data']:
  848. if app_info['appId'] in app_id_array:
  849. app_dict[app_info['appVersion']] = app_info
  850. video_list = get_history_video_info(account_id=account_id,
  851. url=get_history_video_url,
  852. start_time=(datetime.datetime.now() + datetime.timedelta(days=-7)).
  853. strftime("%Y-%m-%d %H:%M:%S"),
  854. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  855. strftime("%Y-%m-%d %H:%M:%S"),
  856. video_cnt=multi_app_id_programme_new_video_cnt,
  857. related_creative_max_cnt=related_creative_max_cnt)
  858. # 单独处理返回的时候中,有通用视频,需要单独处理
  859. # "photo_name": "all",
  860. # "photo_name": "ksjytdrca-糖豆人冲啊",
  861. if video_list['code'] == 0:
  862. video_df = pd.DataFrame(video_list['data'])
  863. # 1-特定视频的创建
  864. special_video_df = video_df[video_df.photo_name != 'all']
  865. for photo_name in special_video_df['photo_name'].unique():
  866. if photo_name in app_dict.keys():
  867. campaign_id = None
  868. app_id = app_dict[photo_name].get('appId', 'error')
  869. app_version = app_dict[photo_name].get('appVersion', 'error')
  870. track_url = app_dict[photo_name].get('trackUrl', 'error')
  871. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  872. campaign_df = pd.read_sql(sql, engine)
  873. for row in campaign_df.itertuples():
  874. if (app_version + '--优选广告位-' + '程序化上新素材') == getattr(row, 'campaign_name'):
  875. campaign_id = getattr(row, 'campaign_id')
  876. break
  877. app_id_video_df = special_video_df[special_video_df.photo_name == photo_name]
  878. app_id_video_list = []
  879. for k, v in app_id_video_df.T.to_dict().items():
  880. app_id_video_list.append(v)
  881. request_data = get_request_data(account_id=account_id,
  882. campaign_id=campaign_id,
  883. video_info=app_id_video_list,
  884. campaign_name=app_version + '--优选广告位-' + '程序化上新素材',
  885. group_name=app_version + '-优选广告位-不限-程序化-' + '上新素材',
  886. ai_strategy_remark="程序化上新素材",
  887. unit_type=7,
  888. app_id=app_id,
  889. click_track_url=track_url,
  890. creative_name=app_version)
  891. request = ai_strategy_request_parse(request_data)
  892. logger.info("account_id=%s, app_id=%s, 程序化上新素材-特定视频,ai策略的返回信息:%s" %
  893. (account_id, app_id, request))
  894. # 2-通用视频的创建,random.shuffle 选择 app_id
  895. general_video_df = video_df[video_df.photo_name == 'all']
  896. general_video_list = []
  897. for k, v in general_video_df.T.to_dict().items():
  898. general_video_list.append(v)
  899. if general_video_list:
  900. app_version_list = list(app_dict)
  901. random.shuffle(app_version_list)
  902. # 每5个通用视频创建一个程序化广告组
  903. batch_num = 5
  904. app_id_cnt = 0
  905. for i in range(0, len(general_video_list), 5):
  906. if i + 5 < len(general_video_list):
  907. batch_general_video = general_video_list[i: i + batch_num]
  908. app_version = app_version_list[app_id_cnt]
  909. app_id = app_dict[app_version].get('appId', 'error')
  910. track_url = app_dict[app_version].get('trackUrl', 'error')
  911. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  912. campaign_df = pd.read_sql(sql, engine)
  913. for row in campaign_df.itertuples():
  914. if (app_version + '--优选广告位-' + '程序化上新素材') == getattr(row, 'campaign_name'):
  915. campaign_id = getattr(row, 'campaign_id')
  916. break
  917. request_data = get_request_data(account_id=account_id,
  918. campaign_id=campaign_id,
  919. video_info=batch_general_video,
  920. campaign_name=app_version + '--优选广告位-' + '程序化上新素材',
  921. group_name=app_version + '-优选广告位-不限-程序化-' + '上新素材',
  922. ai_strategy_remark="程序化上新素材",
  923. unit_type=7,
  924. app_id=app_id,
  925. click_track_url=track_url,
  926. creative_name=app_version)
  927. request = ai_strategy_request_parse(request_data)
  928. app_id_cnt += 1
  929. logger.info("account_id=%s, app_id=%s, 程序化上新素材-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  930. else:
  931. batch_general_video = general_video_list[i: len(general_video_list)]
  932. app_version = app_version_list[app_id_cnt]
  933. app_id = app_dict[app_version].get('appId', 'error')
  934. track_url = app_dict[app_version].get('trackUrl', 'error')
  935. sql = """ select campaign_id, campaign_name from ctop_kuaishou_campaign where account_id = %s """ % account_id
  936. campaign_df = pd.read_sql(sql, engine)
  937. for row in campaign_df.itertuples():
  938. if (app_version + '--优选广告位-' + '程序化上新素材') == getattr(row, 'campaign_name'):
  939. campaign_id = getattr(row, 'campaign_id')
  940. break
  941. request_data = get_request_data(account_id=account_id,
  942. campaign_id=campaign_id,
  943. video_info=batch_general_video,
  944. campaign_name=app_version + '--优选广告位-' + '程序化上新素材',
  945. group_name=app_version + '-优选广告位-不限-程序化-' + '上新素材',
  946. ai_strategy_remark="程序化上新素材",
  947. unit_type=7,
  948. app_id=app_id,
  949. click_track_url=track_url,
  950. creative_name=app_version)
  951. request = ai_strategy_request_parse(request_data)
  952. logger.info("account_id=%s, app_id=%s, 程序化上新素材-通用视频,ai策略的返回信息:%s" % (account_id, app_id, request))
  953. else:
  954. logger.info("account_id=%s, 程序化上新素材: 返回的视频中没有通用视频" % account_id)
  955. self.write(json.dumps({"message": "account_id=%s, 程序化上新素材请求已走完!" % account_id}))
  956. self.flush()
  957. else:
  958. video_info = get_history_video_info(account_id=account_id,
  959. url=get_history_video_url,
  960. start_time=(datetime.datetime.now() + datetime.timedelta(days=-7)).
  961. strftime("%Y-%m-%d %H:%M:%S"),
  962. end_time=(datetime.datetime.now() + datetime.timedelta(days=-1)).
  963. strftime("%Y-%m-%d %H:%M:%S"),
  964. video_cnt=programme_new_video_cnt,
  965. related_creative_max_cnt=related_creative_max_cnt)
  966. if video_info['code'] != 0:
  967. self.write(json.dumps({"account_id": account_id,
  968. "message": "程序化上新素材,没有获取到视频,不发送ai策略请求!"}))
  969. self.flush()
  970. else:
  971. campaign_name, group_name = get_campaign_and_group_name_rule(account_id)
  972. if (campaign_name is None) or (group_name is None):
  973. logger.info("没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!")
  974. self.write(json.dumps({"message": "没有获取到广告计划命名规则 或 广告组命名规则,不发送ai策略请求!"}))
  975. self.flush()
  976. else:
  977. request_data = get_request_data(account_id=account_id,
  978. campaign_id=campaign_id,
  979. video_info=video_info['data'],
  980. campaign_name=campaign_name,
  981. group_name=group_name,
  982. ai_strategy_remark="程序化上新素材",
  983. name_replace="程序化上新素材",
  984. unit_type=7)
  985. request = ai_strategy_request_parse(request_data)
  986. logger.info("account_id = %s, 程序化上新素材,ai策略的返回信息:%s" % (account_id, request))
  987. self.write(json.dumps(request))
  988. self.flush()
  989. except Exception:
  990. logger.error("account_id = %s, traceback is %s" % (account_id, traceback.format_exc()))
  991. self.write(json.dumps({"account_id": account_id, "message": traceback.format_exc(), "code": -1}))
  992. self.flush()