|
|
@@ -0,0 +1,1014 @@
|
|
|
+package com.tzld.ad.job.adPut;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.aliyun.odps.data.Record;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
|
+import com.tzld.ad.dao.mapper.adPut.*;
|
|
|
+import com.tzld.ad.dao.mapper.adPut.ext.AdPutTencentExtMapper;
|
|
|
+import com.tzld.ad.enums.EnumRedisPrefix;
|
|
|
+import com.tzld.ad.model.adPut.*;
|
|
|
+import com.tzld.ad.model.aigc.GoogleLLMResult;
|
|
|
+import com.tzld.ad.model.po.adput.*;
|
|
|
+import com.tzld.ad.service.AdOwnRedisUtils;
|
|
|
+import com.tzld.ad.service.adput.AdPutTencentCommonService;
|
|
|
+import com.tzld.ad.service.aigc.AigcApiService;
|
|
|
+import com.tzld.ad.service.aigc.VideoSearchApiService;
|
|
|
+import com.tzld.ad.service.mongo.AdplatformMongoService;
|
|
|
+import com.tzld.ad.util.AliOssFileTool;
|
|
|
+import com.tzld.ad.util.CollectionUtil;
|
|
|
+import com.tzld.ad.util.DateUtils;
|
|
|
+import com.tzld.ad.util.OdpsUtil;
|
|
|
+import com.xxl.job.core.biz.model.ReturnT;
|
|
|
+import com.xxl.job.core.handler.annotation.XxlJob;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.CountDownLatch;
|
|
|
+import java.util.concurrent.LinkedBlockingQueue;
|
|
|
+import java.util.concurrent.ThreadPoolExecutor;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+
|
|
|
+@Component
|
|
|
+public class AdPutTencentDataJob {
|
|
|
+
|
|
|
+ private final static Logger log = LoggerFactory.getLogger(AdPutTencentDataJob.class);
|
|
|
+
|
|
|
+ ThreadPoolExecutor adPutTencentDataJobExecutor = new ThreadPoolExecutor(128, 128, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(100000),
|
|
|
+ new ThreadFactoryBuilder().setNameFormat("ad-put-tencent-data-pool-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentCommonService adPutTencentCommonService;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentAccountMapper adPutTencentAccountMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentAdMapper adPutTencentAdMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentCreativeMapper adPutTencentCreativeMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentCreativeDataMapper adPutTencentCreativeDataMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentComponentMapper adPutTencentComponentMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentComponentDataMapper adPutTencentComponentDataMapper;
|
|
|
+ @Autowired
|
|
|
+ private AdPutTencentExtMapper adPutTencentExtMapper;
|
|
|
+ @Resource
|
|
|
+ private AdPutTencentBehaviorLogMapper adPutTencentBehaviorLogMapper;
|
|
|
+ @Resource
|
|
|
+ private AdOwnRedisUtils adOwnRedisUtils;
|
|
|
+ @Resource
|
|
|
+ private AigcApiService aigcApiService;
|
|
|
+ @Resource
|
|
|
+ private AdPutTencentCreativeAnalysisMapper adPutTencentCreativeAnalysisMapper;
|
|
|
+ @Resource
|
|
|
+ private AdPutTencentAdPackageMappingMapper adPutTencentAdPackageMappingMapper;
|
|
|
+ @Resource
|
|
|
+ private DailyCategoryVideoMapper dailyCategoryVideoMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private VideoSearchApiService videoSearchApiService;
|
|
|
+
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private AdplatformMongoService adplatformMongoService;
|
|
|
+
|
|
|
+ public static final ThreadPoolExecutor DATA_EXECUTOR = new ThreadPoolExecutor(
|
|
|
+ 5, 5, 10L, TimeUnit.MINUTES,
|
|
|
+ new LinkedBlockingQueue<>(),
|
|
|
+ new ThreadFactoryBuilder().setNameFormat("ad-put-tencent-data-pool-%d").build(),
|
|
|
+ new ThreadPoolExecutor.CallerRunsPolicy()
|
|
|
+ );
|
|
|
+
|
|
|
+ @Value("${analysis.title.category.prompt:}")
|
|
|
+ private String analysisTitleCategoryPrompt;
|
|
|
+
|
|
|
+ @Value("${daily.refresh.creative.analysis.video.min.cost:10000}")
|
|
|
+ private Long dailyRefreshCreativeAnalysisVideoMinCost;
|
|
|
+ @Value("${daily.refresh.creative.analysis.video.start.date:1}")
|
|
|
+ private Integer dailyRefreshCreativeAnalysisVideoStartDate;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 账号获取广告内容
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("getAdDataByAccountJob")
|
|
|
+ public ReturnT<String> getAdDataByAccountJob(String param) {
|
|
|
+ // 查询所有已授权的账户
|
|
|
+ AdPutTencentAccountExample adPutTencentAccountExample = new AdPutTencentAccountExample();
|
|
|
+ adPutTencentAccountExample.createCriteria().andIsDeleteEqualTo(0).andStatusEqualTo(1);
|
|
|
+ List<AdPutTencentAccount> adPutTencentAccounts = adPutTencentAccountMapper.selectByExample(adPutTencentAccountExample);
|
|
|
+ for (AdPutTencentAccount adPutTencentAccount : adPutTencentAccounts) {
|
|
|
+ List<AdPutTencentAdGroupInfo> adGroupInfoByAccounts = adPutTencentCommonService.getAllAdGroupInfoByAccount(adPutTencentAccount.getAccountId());
|
|
|
+ if (CollectionUtil.isEmpty(adGroupInfoByAccounts)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ List<Long> adIds = adGroupInfoByAccounts.stream().map(AdPutTencentAdGroupInfo::getAdgroup_id).collect(Collectors.toList());
|
|
|
+ AdPutTencentAdPackageMappingExample adPutTencentAdPackageMappingExample = new AdPutTencentAdPackageMappingExample();
|
|
|
+ adPutTencentAdPackageMappingExample.createCriteria().andAdIdIn(adIds);
|
|
|
+ List<AdPutTencentAdPackageMapping> adPackageMappingList = adPutTencentAdPackageMappingMapper.selectByExample(adPutTencentAdPackageMappingExample);
|
|
|
+ Map<Long, Map<Long, AdPutTencentAdPackageMapping>> adIdToPackageMappingMap = adPackageMappingList.stream()
|
|
|
+ .collect(Collectors.groupingBy(AdPutTencentAdPackageMapping::getAdId,
|
|
|
+ Collectors.toMap(AdPutTencentAdPackageMapping::getPackageId, Function.identity())));
|
|
|
+ // 更新广告信息
|
|
|
+ for (AdPutTencentAdGroupInfo adGroupInfoByAccount : adGroupInfoByAccounts) {
|
|
|
+ try {
|
|
|
+ AdPutTencentAdExample adPutTencentAdExample = new AdPutTencentAdExample();
|
|
|
+ adPutTencentAdExample.createCriteria().andIsDeleteEqualTo(0).andAdIdEqualTo(adGroupInfoByAccount.getAdgroup_id());
|
|
|
+ List<AdPutTencentAd> adPutTencentAds = adPutTencentAdMapper.selectByExample(adPutTencentAdExample);
|
|
|
+ if (CollectionUtil.isEmpty(adPutTencentAds)) {
|
|
|
+ // 插入
|
|
|
+ AdPutTencentAd adPutTencentAd = new AdPutTencentAd();
|
|
|
+ setAdGroupInfoVo(adGroupInfoByAccount, adPutTencentAd, adPutTencentAccount.getAccountId());
|
|
|
+ adPutTencentAdMapper.insertSelective(adPutTencentAd);
|
|
|
+ } else {
|
|
|
+ // 更新
|
|
|
+ AdPutTencentAd adPutTencentAd = adPutTencentAds.get(0);
|
|
|
+ setAdGroupInfoVo(adGroupInfoByAccount, adPutTencentAd, adPutTencentAccount.getAccountId());
|
|
|
+ adPutTencentAd.setUpdateTime(new Date());
|
|
|
+ adPutTencentAdMapper.updateByPrimaryKey(adPutTencentAd);
|
|
|
+ }
|
|
|
+ Map<Long, AdPutTencentAdPackageMapping> packageMappingMap = adIdToPackageMappingMap.getOrDefault(adGroupInfoByAccount.getAdgroup_id(), Collections.emptyMap());
|
|
|
+ // 更新广告人群包关系
|
|
|
+ if (Objects.nonNull(adGroupInfoByAccount.getTargeting())
|
|
|
+ && !CollectionUtil.isEmpty(adGroupInfoByAccount.getTargeting().getCustom_audience())) {
|
|
|
+ List<Long> customAudienceIds = adGroupInfoByAccount.getTargeting().getCustom_audience();
|
|
|
+ for (Long customAudienceId : customAudienceIds) {
|
|
|
+ if (packageMappingMap.containsKey(customAudienceId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ AdPutTencentAdPackageMapping adPackageMapping = new AdPutTencentAdPackageMapping();
|
|
|
+ adPackageMapping.setAdId(adGroupInfoByAccount.getAdgroup_id());
|
|
|
+ adPackageMapping.setPackageId(customAudienceId);
|
|
|
+ adPackageMapping.setIsDelete(0);
|
|
|
+ adPackageMapping.setCreateTime(new Date());
|
|
|
+ adPackageMapping.setUpdateTime(new Date());
|
|
|
+ adPutTencentAdPackageMappingMapper.insertSelective(adPackageMapping);
|
|
|
+ }
|
|
|
+ for (Map.Entry<Long, AdPutTencentAdPackageMapping> entry : packageMappingMap.entrySet()) {
|
|
|
+ Long packageId = entry.getKey();
|
|
|
+ AdPutTencentAdPackageMapping adPackageMapping = entry.getValue();
|
|
|
+ if (customAudienceIds.contains(packageId) || adPackageMapping.getIsDelete() == 1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ adPackageMapping.setIsDelete(1);
|
|
|
+ adPackageMapping.setUpdateTime(new Date());
|
|
|
+ adPutTencentAdPackageMappingMapper.updateByPrimaryKey(adPackageMapping);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("getAdDataByAccountJob update ad package mapping error, adGroupInfoByAccount:{}",
|
|
|
+ JSONObject.toJSONString(adGroupInfoByAccount));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //清理查不到的数据
|
|
|
+ try {
|
|
|
+ List<Long> adGroupIdList = adGroupInfoByAccounts.stream().map(AdPutTencentAdGroupInfo::getAdgroup_id).collect(Collectors.toList());
|
|
|
+ AdPutTencentAdExample adPutTencentAdExample = new AdPutTencentAdExample();
|
|
|
+ adPutTencentAdExample.createCriteria().andIsDeleteEqualTo(0).andAccountIdEqualTo(Long.valueOf(adPutTencentAccount.getAccountId())).andAdIdNotIn(adGroupIdList);
|
|
|
+ List<AdPutTencentAd> needRemoveList = adPutTencentAdMapper.selectByExample(adPutTencentAdExample);
|
|
|
+ if (!CollectionUtils.isEmpty(needRemoveList)) {
|
|
|
+ List<Long> needRemoveAdId = needRemoveList.stream().map(AdPutTencentAd::getAdId).collect(Collectors.toList());
|
|
|
+ log.info("getAdDataByAccountJob, need remove ad, needRemoveAdId:{}, accountId:{}", JSONObject.toJSONString(needRemoveAdId), adPutTencentAccount.getAccountId());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("getAdDataByAccountJob clear data error");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ // 同步创意数据
|
|
|
+ getCreativeDataByAdJob(param);
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 广告获取创意内容
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("getCreativeDataByAdJob")
|
|
|
+ public ReturnT<String> getCreativeDataByAdJob(String param) {
|
|
|
+ // 查询所有广告
|
|
|
+ AdPutTencentAdExample adPutTencentAdExample = new AdPutTencentAdExample();
|
|
|
+ adPutTencentAdExample.createCriteria().andIsDeleteEqualTo(0);
|
|
|
+ List<AdPutTencentAd> adPutTencentAds = adPutTencentAdMapper.selectByExample(adPutTencentAdExample);
|
|
|
+ if (!CollectionUtil.isEmpty(adPutTencentAds)) {
|
|
|
+ Set<Long> accountIds = adPutTencentAds.parallelStream().map(AdPutTencentAd::getAccountId).collect(Collectors.toSet());
|
|
|
+ for (Long accountId : accountIds) {
|
|
|
+ List<String> adIds = adPutTencentAds.stream().filter(x -> x.getAccountId().equals(accountId)).map(x -> x.getAdId() + "").collect(Collectors.toList());
|
|
|
+ List<AdPutTencentCreativeInfo> adTencentCreativeInfos = adPutTencentCommonService.getAllCreativeByAds(accountId, adIds);
|
|
|
+ if (CollectionUtil.isEmpty(adTencentCreativeInfos)) {
|
|
|
+ log.error("getCreativeDataByAdJob is null accountId:" + accountId + ",adIds:" + JSON.toJSONString(adIds));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ log.info("AdPutTencentDataJob.getCreativeDataByAdJob, adTencentCreativeInfos:{}", JSONObject.toJSONString(adTencentCreativeInfos));
|
|
|
+ for (AdPutTencentCreativeInfo adTencentCreativeInfo : adTencentCreativeInfos) {
|
|
|
+ AdPutTencentCreativeExample adPutTencentCreativeExample = new AdPutTencentCreativeExample();
|
|
|
+ adPutTencentCreativeExample.createCriteria().andIsDeleteEqualTo(0).andCreativeIdEqualTo(adTencentCreativeInfo.getDynamic_creative_id());
|
|
|
+ List<AdPutTencentCreative> adPutTencentCreatives = adPutTencentCreativeMapper.selectByExampleWithBLOBs(adPutTencentCreativeExample);
|
|
|
+ log.info("AdPutTencentDataJob.getCreativeDataByAdJob.getLocalCreatives, creative_id:{}, creatives:{}", adTencentCreativeInfo.getDynamic_creative_id(), JSONObject.toJSONString(adPutTencentCreatives));
|
|
|
+ if (CollectionUtil.isEmpty(adPutTencentCreatives)) {
|
|
|
+ // 插入
|
|
|
+ AdPutTencentCreative adPutTencentCreative = new AdPutTencentCreative();
|
|
|
+ setCreativeVo(adTencentCreativeInfo, adPutTencentCreative, adTencentCreativeInfo.getAdgroup_id(), accountId);
|
|
|
+ adPutTencentCreativeMapper.insertSelective(adPutTencentCreative);
|
|
|
+ // 处理 落地页内容
|
|
|
+ adPutTencentCommonService.handleCreativeComponents(adPutTencentCreative.getCreativeId(), adTencentCreativeInfo.getCreative_components());
|
|
|
+ } else {
|
|
|
+ // 更新
|
|
|
+ AdPutTencentCreative adPutTencentCreative = adPutTencentCreatives.get(0);
|
|
|
+ setCreativeVo(adTencentCreativeInfo, adPutTencentCreative, adTencentCreativeInfo.getAdgroup_id(), accountId);
|
|
|
+ adPutTencentCreative.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeMapper.updateByPrimaryKeySelective(adPutTencentCreative);
|
|
|
+ // 处理 落地页内容
|
|
|
+ adPutTencentCommonService.handleCreativeComponents(adPutTencentCreative.getCreativeId(), adTencentCreativeInfo.getCreative_components());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 广告获取创意内容
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("checkCreativeDeletedJob")
|
|
|
+ public ReturnT<String> checkCreativeDeletedJob(String param) {
|
|
|
+ // 查询所有创意
|
|
|
+ AdPutTencentCreativeExample adPutTencentCreativeExample = new AdPutTencentCreativeExample();
|
|
|
+ adPutTencentCreativeExample.createCriteria().andIsDeleteEqualTo(0);
|
|
|
+ List<AdPutTencentCreative> adPutTencentCreatives = adPutTencentCreativeMapper.selectByExample(adPutTencentCreativeExample);
|
|
|
+ if (!CollectionUtil.isEmpty(adPutTencentCreatives)) {
|
|
|
+ Set<Long> accountIds = adPutTencentCreatives.parallelStream().map(AdPutTencentCreative::getAccountId).collect(Collectors.toSet());
|
|
|
+ Map<Long, AdPutTencentCreative> creativeMap = adPutTencentCreatives.stream().collect(Collectors.toMap(AdPutTencentCreative::getCreativeId, x -> x));
|
|
|
+ for (Long accountId : accountIds) {
|
|
|
+ List<AdPutTencentCreative> creativeList = adPutTencentCreatives.stream().filter(x -> x.getAccountId().equals(accountId)).collect(Collectors.toList());
|
|
|
+ List<String> creativeIds = creativeList.stream().map(x -> x.getCreativeId() + "").collect(Collectors.toList());
|
|
|
+ List<AdPutTencentCreativeInfo> adTencentCreativeInfos = adPutTencentCommonService.getAllCreativeByCreatives(accountId, creativeIds);
|
|
|
+ if (CollectionUtil.isEmpty(adTencentCreativeInfos)) {
|
|
|
+ log.error("getCreativeDataByAdJob is null accountId:" + accountId + ",creativeIds:" + JSON.toJSONString(creativeIds));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ log.info("AdPutTencentDataJob.checkCreativeDeletedJob, adTencentCreativeInfos:{}", JSONObject.toJSONString(adTencentCreativeInfos));
|
|
|
+ for (AdPutTencentCreativeInfo adTencentCreativeInfo : adTencentCreativeInfos) {
|
|
|
+ // 更新
|
|
|
+ AdPutTencentCreative adPutTencentCreative = creativeMap.get(adTencentCreativeInfo.getDynamic_creative_id());
|
|
|
+ if (adPutTencentCreative == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ setCreativeVo(adTencentCreativeInfo, adPutTencentCreative, adTencentCreativeInfo.getAdgroup_id(), accountId);
|
|
|
+ adPutTencentCreative.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeMapper.updateByPrimaryKeySelective(adPutTencentCreative);
|
|
|
+ // 处理 落地页内容
|
|
|
+ adPutTencentCommonService.handleCreativeComponents(adPutTencentCreative.getCreativeId(), adTencentCreativeInfo.getCreative_components());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新当日创意数据
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("updateDayTencentCreativeData")
|
|
|
+ public ReturnT<String> updateDayTencentCreativeData(String param) {
|
|
|
+ String dayStr = getDayStr();
|
|
|
+ if (StringUtils.isNotBlank(param)) {
|
|
|
+ dayStr = param;
|
|
|
+ }
|
|
|
+ AdPutTencentCreativeExample adPutTencentCreativeExample = new AdPutTencentCreativeExample();
|
|
|
+ adPutTencentCreativeExample.createCriteria().andIsDeleteEqualTo(0).andIsGetDataEqualTo(1).andCreativeStatusEqualTo("AD_STATUS_NORMAL");
|
|
|
+ adPutTencentCreativeExample.setOrderByClause("id desc");
|
|
|
+ List<AdPutTencentCreative> adPutTencentCreatives = adPutTencentCreativeMapper.selectByExample(adPutTencentCreativeExample);
|
|
|
+ CountDownLatch cdl = new CountDownLatch(adPutTencentCreatives.size());
|
|
|
+ for (AdPutTencentCreative adPutTencentCreative : adPutTencentCreatives) {
|
|
|
+ String finalDayStr = dayStr;
|
|
|
+ DATA_EXECUTOR.submit(() -> {
|
|
|
+ try {
|
|
|
+ List<AdPutTencentCreativeCostData> creativeCostData = adPutTencentCommonService
|
|
|
+ .getCreativeCostData(adPutTencentCreative.getAccountId() + "", adPutTencentCreative.getCreativeId() + "",
|
|
|
+ finalDayStr, finalDayStr, null, null);
|
|
|
+ if (CollectionUtil.isEmpty(creativeCostData)) {
|
|
|
+ log.warn("getCreativeData is null accountId:" + adPutTencentCreative.getAccountId() + ",creativeId:" + adPutTencentCreative.getCreativeId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+// log.info("updateDayTencentCreativeData.creativeCostData, creativeCostData:{}", JSONObject.toJSONString(creativeCostData));
|
|
|
+ AdPutTencentCreativeData adPutTencentCreativeData = getAdPutTencentCreativeData(adPutTencentCreative, creativeCostData);
|
|
|
+ // 插入还是更新
|
|
|
+ AdPutTencentCreativeDataExample adPutTencentCreativeDataExample = new AdPutTencentCreativeDataExample();
|
|
|
+ adPutTencentCreativeDataExample.createCriteria().andCreativeIdEqualTo(adPutTencentCreative.getCreativeId()).andDtEqualTo(finalDayStr);
|
|
|
+ List<AdPutTencentCreativeData> adPutTencentCreativeDataExist = adPutTencentCreativeDataMapper.selectByExample(adPutTencentCreativeDataExample);
|
|
|
+ if (!CollectionUtil.isEmpty(adPutTencentCreativeDataExist)) {
|
|
|
+ AdPutTencentCreativeData adPutTencentCreativeData1 = adPutTencentCreativeDataExist.get(0);
|
|
|
+ adPutTencentCreativeData.setId(adPutTencentCreativeData1.getId());
|
|
|
+ adPutTencentCreativeData.setCreateTime(adPutTencentCreativeData1.getCreateTime());
|
|
|
+ adPutTencentCreativeData.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeDataMapper.updateByPrimaryKeySelective(adPutTencentCreativeData);
|
|
|
+ } else {
|
|
|
+ adPutTencentCreativeDataMapper.insertSelective(adPutTencentCreativeData);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ cdl.countDown();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ cdl.await();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("updateDayTencentCreativeData cdl await error", e);
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新昨日消耗数据
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("updateLastDayTencentCreativeData")
|
|
|
+ public ReturnT<String> updateLastDayTencentCreativeData(String param) {
|
|
|
+ String lastDayStr = getLastDayStr();
|
|
|
+ if (StringUtils.isNotBlank(param)) {
|
|
|
+ lastDayStr = param;
|
|
|
+ }
|
|
|
+ AdPutTencentCreativeExample adPutTencentCreativeExample = new AdPutTencentCreativeExample();
|
|
|
+ adPutTencentCreativeExample.createCriteria().andIsDeleteEqualTo(0).andIsGetDataEqualTo(1).andCreativeStatusEqualTo("AD_STATUS_NORMAL");
|
|
|
+ adPutTencentCreativeExample.setOrderByClause("id desc");
|
|
|
+ List<AdPutTencentCreative> adPutTencentCreatives = adPutTencentCreativeMapper.selectByExample(adPutTencentCreativeExample);
|
|
|
+ CountDownLatch cdl = new CountDownLatch(adPutTencentCreatives.size());
|
|
|
+ for (AdPutTencentCreative adPutTencentCreative : adPutTencentCreatives) {
|
|
|
+ String finalLastDayStr = lastDayStr;
|
|
|
+ DATA_EXECUTOR.submit(() -> {
|
|
|
+ try {
|
|
|
+ List<AdPutTencentCreativeCostData> creativeCostData = adPutTencentCommonService.getCreativeCostData(
|
|
|
+ String.valueOf(adPutTencentCreative.getAccountId()), String.valueOf(adPutTencentCreative.getCreativeId()),
|
|
|
+ finalLastDayStr, finalLastDayStr, null, null);
|
|
|
+ if (CollectionUtil.isEmpty(creativeCostData)) {
|
|
|
+ log.warn("getCreativeData is null accountId:" + adPutTencentCreative.getAccountId() + ",creativeId:" + adPutTencentCreative.getCreativeId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 删除昨日数据
|
|
|
+ AdPutTencentCreativeDataExample deleteExample = new AdPutTencentCreativeDataExample();
|
|
|
+ deleteExample.createCriteria().andDtEqualTo(finalLastDayStr).andCreativeIdEqualTo(adPutTencentCreative.getCreativeId());
|
|
|
+ adPutTencentCreativeDataMapper.deleteByExample(deleteExample);
|
|
|
+ AdPutTencentCreativeData adPutTencentCreativeData = getAdPutTencentCreativeData(adPutTencentCreative, creativeCostData);
|
|
|
+ adPutTencentCreativeDataMapper.insertSelective(adPutTencentCreativeData);
|
|
|
+
|
|
|
+ } finally {
|
|
|
+ cdl.countDown();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ cdl.await();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("updateLastDayTencentCreativeData cdl await error", e);
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ private AdPutTencentCreativeData getAdPutTencentCreativeData(AdPutTencentCreative adPutTencentCreative, List<AdPutTencentCreativeCostData> creativeCostData) {
|
|
|
+ AdPutTencentCreativeCostData adPutTencentCreativeCostData = creativeCostData.get(0);
|
|
|
+ AdPutTencentCreativeData adPutTencentCreativeData = new AdPutTencentCreativeData();
|
|
|
+ adPutTencentCreativeData.setCreativeId(adPutTencentCreative.getCreativeId());
|
|
|
+ adPutTencentCreativeData.setValidClickCount(adPutTencentCreativeCostData.getValid_click_count());
|
|
|
+ adPutTencentCreativeData.setClickUserCount(adPutTencentCreativeCostData.getClick_user_count());
|
|
|
+ adPutTencentCreativeData.setViewCount(adPutTencentCreativeCostData.getView_count());
|
|
|
+ adPutTencentCreativeData.setViewUserCount(adPutTencentCreativeCostData.getView_user_count());
|
|
|
+ adPutTencentCreativeData.setAvgViewPerUser(adPutTencentCreativeCostData.getAvg_view_per_user());
|
|
|
+ adPutTencentCreativeData.setCost(adPutTencentCreativeCostData.getCost());
|
|
|
+ adPutTencentCreativeData.setCpc(adPutTencentCreativeCostData.getCpc());
|
|
|
+ adPutTencentCreativeData.setCtr(adPutTencentCreativeCostData.getCtr());
|
|
|
+ adPutTencentCreativeData.setConversionsCount(adPutTencentCreativeCostData.getConversions_count());
|
|
|
+ adPutTencentCreativeData.setDt(adPutTencentCreativeCostData.getDate());
|
|
|
+ adPutTencentCreativeData.setFromFollowUv(adPutTencentCreativeCostData.getFrom_follow_uv());
|
|
|
+ adPutTencentCreativeData.setKeyPageViewCount(adPutTencentCreativeCostData.getKey_page_view_count());
|
|
|
+ adPutTencentCreativeData.setRegisterByClickCount(adPutTencentCreativeCostData.getRegister_by_click_count());
|
|
|
+ adPutTencentCreativeData.setFromFollowByClickUv(adPutTencentCreativeCostData.getFrom_follow_by_click_uv());
|
|
|
+ adPutTencentCreativeData.setBizFollowUv(adPutTencentCreativeCostData.getBiz_follow_uv());
|
|
|
+ adPutTencentCreativeData.setRegPv(adPutTencentCreativeCostData.getReg_pv());
|
|
|
+ return adPutTencentCreativeData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新昨日组件数据
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("updateLastDayTencentComponent")
|
|
|
+ public ReturnT<String> updateLastDayTencentComponent(String param) {
|
|
|
+ String lastDayStr = getLastDayStr();
|
|
|
+ if (StringUtils.isNotBlank(param)) {
|
|
|
+ lastDayStr = param;
|
|
|
+ }
|
|
|
+ updateTencentComponent(lastDayStr);
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新今日组件数据
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @XxlJob("updateTodayTencentComponent")
|
|
|
+ public ReturnT<String> updateTodayTencentComponent(String param) {
|
|
|
+ String todayStr = getDayStr();
|
|
|
+ if (StringUtils.isNotBlank(param)) {
|
|
|
+ todayStr = param;
|
|
|
+ }
|
|
|
+ updateTencentComponent(todayStr);
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateTencentComponent(String dateStr) {
|
|
|
+ // 查询所有已授权的账户
|
|
|
+ AdPutTencentAccountExample adPutTencentAccountExample = new AdPutTencentAccountExample();
|
|
|
+ adPutTencentAccountExample.createCriteria().andIsDeleteEqualTo(0).andStatusEqualTo(1);
|
|
|
+ List<AdPutTencentAccount> adPutTencentAccounts = adPutTencentAccountMapper.selectByExample(adPutTencentAccountExample);
|
|
|
+ for (AdPutTencentAccount adPutTencentAccount : adPutTencentAccounts) {
|
|
|
+ try {
|
|
|
+ List<AdPutTencentComponentDailyData> creativeComponentDataList = adPutTencentCommonService.getComponentData(
|
|
|
+ adPutTencentAccount.getAccountId(), dateStr, dateStr, null, null);
|
|
|
+ if (CollectionUtil.isEmpty(creativeComponentDataList)) {
|
|
|
+ log.warn("getCreativeComponentData is null accountId:" + adPutTencentAccount.getAccountId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 统计数据save
|
|
|
+ List<AdPutTencentComponentData> saveList = new ArrayList<>();
|
|
|
+ for (AdPutTencentComponentDailyData creativeComponentData : creativeComponentDataList) {
|
|
|
+ AdPutTencentComponentData adPutTencentComponentData = getAdPutTencentComponentData(dateStr, creativeComponentData);
|
|
|
+ saveList.add(adPutTencentComponentData);
|
|
|
+ }
|
|
|
+ // 删除历史
|
|
|
+ List<Long> creativeIds = saveList.stream().map(AdPutTencentComponentData::getCreativeId).collect(Collectors.toList());
|
|
|
+ AdPutTencentComponentDataExample deleteExample = new AdPutTencentComponentDataExample();
|
|
|
+ deleteExample.createCriteria().andDtEqualTo(dateStr).andCreativeIdIn(creativeIds);
|
|
|
+ adPutTencentComponentDataMapper.deleteByExample(deleteExample);
|
|
|
+ // save
|
|
|
+ adPutTencentExtMapper.batchInsertComponentData(saveList);
|
|
|
+ // 获取素材详情
|
|
|
+ List<String> componentIds = creativeComponentDataList.stream()
|
|
|
+ .filter(o -> o.getComponentID() > 0)
|
|
|
+ .map(x -> String.valueOf(x.getComponentID()))
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ List<AdPutTencentComponentDetail> detailList = new ArrayList<>();
|
|
|
+ for (List<String> partition : Lists.partition(componentIds, 100)) {
|
|
|
+ detailList.addAll(adPutTencentCommonService.getComponentDetail(
|
|
|
+ adPutTencentAccount.getAccountId(), partition, null, null));
|
|
|
+ }
|
|
|
+ for (AdPutTencentComponentDetail detail : detailList) {
|
|
|
+ AdPutTencentComponentDetail.ComponentValue componentValue = detail.getComponentValue();
|
|
|
+ List<AdPutTencentComponentVideo> componentVideoList = new ArrayList<>();
|
|
|
+ List<AdPutTencentComponentImage> componentImageList = new ArrayList<>();
|
|
|
+ // videoUrl get
|
|
|
+ if (Objects.nonNull(componentValue) && Objects.nonNull(componentValue.getVideo())) {
|
|
|
+ List<String> videoIds = Collections.singletonList(detail.getComponentValue().getVideo().getValue().getVideoID());
|
|
|
+ componentVideoList.addAll(adPutTencentCommonService.getComponentVideo(
|
|
|
+ adPutTencentAccount.getAccountId(), videoIds, null, null));
|
|
|
+ }
|
|
|
+ // imageUrl get
|
|
|
+ if (Objects.nonNull(componentValue) && Objects.nonNull(componentValue.getImage())) {
|
|
|
+ List<String> imageIds = Collections.singletonList(detail.getComponentValue().getImage().getValue().getImageID());
|
|
|
+ componentImageList.addAll(adPutTencentCommonService.getComponentImage(
|
|
|
+ adPutTencentAccount.getAccountId(), imageIds, null, null));
|
|
|
+ }
|
|
|
+ // 非图片视频组件过滤
|
|
|
+ if (CollectionUtil.isEmpty(componentVideoList) && CollectionUtil.isEmpty(componentImageList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // save
|
|
|
+ AdPutTencentComponent adPutTencentComponent = getAdPutTencentComponent(detail, componentVideoList, componentImageList);
|
|
|
+ AdPutTencentComponentExample example = new AdPutTencentComponentExample();
|
|
|
+ example.createCriteria().andAccountIdEqualTo(adPutTencentComponent.getAccountId())
|
|
|
+ .andComponentIdEqualTo(adPutTencentComponent.getComponentId());
|
|
|
+ long exists = adPutTencentComponentMapper.countByExample(example);
|
|
|
+ if (exists == 0) {
|
|
|
+ adPutTencentComponentMapper.insertSelective(adPutTencentComponent);
|
|
|
+ } else {
|
|
|
+ adPutTencentComponent.setUpdateTime(new Date());
|
|
|
+ adPutTencentComponentMapper.updateByExampleSelective(adPutTencentComponent, example);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("updateLastDayTencentComponent Error AccountId:{}", adPutTencentAccount.getAccountId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private AdPutTencentComponentData getAdPutTencentComponentData(String lastDayStr, AdPutTencentComponentDailyData data) {
|
|
|
+ AdPutTencentComponentData item = new AdPutTencentComponentData();
|
|
|
+ item.setDt(lastDayStr);
|
|
|
+ item.setComponentId(data.getComponentID());
|
|
|
+ item.setCreativeId(data.getDynamicCreativeId());
|
|
|
+ item.setValidClickCount(data.getValidClickCount());
|
|
|
+ item.setViewCount(data.getViewCount());
|
|
|
+ item.setCtr(data.getCtr());
|
|
|
+ item.setCpc(data.getCpc());
|
|
|
+ item.setCost(data.getCost());
|
|
|
+ item.setConversionsCount(data.getConversionsCount());
|
|
|
+ item.setFromFollowUv(data.getFromFollowUv());
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ private AdPutTencentComponent getAdPutTencentComponent(AdPutTencentComponentDetail componentDetail,
|
|
|
+ List<AdPutTencentComponentVideo> componentVideoList,
|
|
|
+ List<AdPutTencentComponentImage> componentImageList) {
|
|
|
+ AdPutTencentComponent component = new AdPutTencentComponent();
|
|
|
+ component.setComponentId(componentDetail.getComponentID());
|
|
|
+ component.setAccountId(componentDetail.getAccountID());
|
|
|
+ component.setComponentCustomName(componentDetail.getComponentCustomName());
|
|
|
+ component.setComponentSubType(componentDetail.getComponentSubType());
|
|
|
+ component.setGenerationType(componentDetail.getGenerationType());
|
|
|
+ component.setIsDeleted((byte) (componentDetail.isDeleted() ? 1 : 0));
|
|
|
+ if (!CollectionUtil.isEmpty(componentImageList)) {
|
|
|
+ component.setImageId(Long.valueOf(componentImageList.get(0).getImageID()));
|
|
|
+ component.setImageUrl(componentImageList.get(0).getPreviewURL());
|
|
|
+ }
|
|
|
+ if (!CollectionUtil.isEmpty(componentVideoList)) {
|
|
|
+ component.setVideoId(componentVideoList.get(0).getVideoID());
|
|
|
+ component.setVideoCoverUrl(componentVideoList.get(0).getKeyFrameImageURL());
|
|
|
+ component.setVideoUrl(componentVideoList.get(0).getPreviewURL());
|
|
|
+ }
|
|
|
+ return component;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setCreativeVo(AdPutTencentCreativeInfo source, AdPutTencentCreative target, Long adId, Long accountId) {
|
|
|
+ target.setAdId(adId);
|
|
|
+ target.setAccountId(accountId);
|
|
|
+ target.setCreativeId(source.getDynamic_creative_id());
|
|
|
+ target.setCreativeName(source.getDynamic_creative_name());
|
|
|
+ target.setCreativeStatus(source.getConfigured_status());
|
|
|
+ target.setCreativeComponents(source.getCreative_components());
|
|
|
+ target.setIsGetData(1);
|
|
|
+ target.setIsDelete(source.getIs_deleted() ? 1 : 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setAdGroupInfoVo(AdPutTencentAdGroupInfo source, AdPutTencentAd target, String accountId) {
|
|
|
+ target.setAdId(source.getAdgroup_id());
|
|
|
+ target.setDayAmount(source.getDaily_budget());
|
|
|
+ target.setAdStatus(source.getConfigured_status());
|
|
|
+ target.setSystemStatus(source.getSystem_status());
|
|
|
+ target.setAdName(source.getAdgroup_name());
|
|
|
+ target.setMarketingGoal(source.getMarketing_goal());
|
|
|
+ target.setMarketingSubGoal(source.getMarketing_sub_goal());
|
|
|
+ target.setMarketingCarrierType(source.getMarketing_carrier_type());
|
|
|
+ target.setMarketingCarrierDetail(source.getMarketing_carrier_detail());
|
|
|
+ target.setBidAmount(source.getBid_amount());
|
|
|
+ target.setAccountId(Long.valueOf(accountId.trim()));
|
|
|
+ target.setOptimizationGoal(source.getOptimization_goal());
|
|
|
+ if (source.getMarketing_asset_outer_spec() != null) {
|
|
|
+ target.setMarketingTargetType(source.getMarketing_asset_outer_spec().getMarketingTargetType());
|
|
|
+ target.setMarketingAssetOuterId(source.getMarketing_asset_outer_spec().getMarketingAssetOuterId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getLastDayStr() {
|
|
|
+ // 获取当前日期
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+
|
|
|
+ // 获取前一日的日期
|
|
|
+ LocalDate yesterday = today.minusDays(1);
|
|
|
+
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ // 将前一日的日期格式化为字符串
|
|
|
+ return yesterday.format(formatter);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getDayStr() {
|
|
|
+ // 获取当前日期
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+
|
|
|
+ // 获取前一日的日期
|
|
|
+// LocalDate yesterday = today.minusDays(1);
|
|
|
+
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ // 将前一日的日期格式化为字符串
|
|
|
+ return today.format(formatter);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getNowDayTimeStr() {
|
|
|
+ // 获取当前日期
|
|
|
+ LocalDateTime today = LocalDateTime.now();
|
|
|
+
|
|
|
+ // 获取前一日的日期
|
|
|
+// LocalDate yesterday = today.minusDays(1);
|
|
|
+
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+
|
|
|
+ // 将前一日的日期格式化为字符串
|
|
|
+ return today.format(formatter);
|
|
|
+ }
|
|
|
+
|
|
|
+ @XxlJob("adPutTencentCreativeAnalysisJob")
|
|
|
+ public ReturnT<String> adPutTencentCreativeAnalysisJob(String param) {
|
|
|
+ Date startTime = DateUtils.getBeforeDateOfTime(new Date(), 7);
|
|
|
+ AdPutTencentCreativeAnalysisExample example = new AdPutTencentCreativeAnalysisExample();
|
|
|
+ example.createCriteria().andStatusEqualTo(0).andCreateTimeGreaterThan(startTime);
|
|
|
+ List<AdPutTencentCreativeAnalysis> analysisList = adPutTencentCreativeAnalysisMapper.selectByExample(example);
|
|
|
+ if (CollectionUtil.isEmpty(analysisList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ List<Long> creativeIds = analysisList.stream().map(AdPutTencentCreativeAnalysis::getCreativeId).collect(Collectors.toList());
|
|
|
+ AdPutTencentComponentDataExample componentDataExample = new AdPutTencentComponentDataExample();
|
|
|
+ componentDataExample.createCriteria().andCreativeIdIn(creativeIds).andCreateTimeGreaterThanOrEqualTo(startTime);
|
|
|
+ List<AdPutTencentComponentData> componentsDataList = adPutTencentComponentDataMapper.selectByExample(componentDataExample);
|
|
|
+ Map<Long, List<AdPutTencentComponentData>> componentsDataMap = componentsDataList.stream().collect(Collectors.groupingBy(AdPutTencentComponentData::getCreativeId));
|
|
|
+
|
|
|
+ List<DailyCategoryVideo> dailyCategoryVideoList = adPutTencentExtMapper.getMaxDailyCategoryVideoList();
|
|
|
+ Map<String, Long> categoryVideoMap = dailyCategoryVideoList.stream().collect(Collectors.toMap(DailyCategoryVideo::getCategory, DailyCategoryVideo::getVideoId));
|
|
|
+ for (AdPutTencentCreativeAnalysis creativeAnalysis : analysisList) {
|
|
|
+ AdPutTencentComponent component = getMaxCostComponent(componentsDataMap, creativeAnalysis.getCreativeId());
|
|
|
+ if (Objects.isNull(component)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ String componentId = component.getComponentId().toString();
|
|
|
+ if (StringUtils.isBlank(creativeAnalysis.getTitle())) {
|
|
|
+ // download & upload to oss
|
|
|
+ String fileName = String.format("adPutTencent/image/%s_%s_%d.jpg", creativeAnalysis.getCreativeId(),
|
|
|
+ componentId, System.currentTimeMillis());
|
|
|
+ String ossImageUrl = AliOssFileTool.downloadAndSaveInOSS(fileName, component.getImageUrl(), "image/jpeg");
|
|
|
+ // 调用gemini模型提取图片中的文字
|
|
|
+ String prompt = "识别图片里的文字,直接输出图片里的文字标题,但是不要输出图片里右下角的字,比如“点开看看”“看这里”等,仅输出标题,不要有多余的文字输出";
|
|
|
+ GoogleLLMResult result = aigcApiService.gemini("gemini-2.0-flash", prompt, Arrays.asList(ossImageUrl));
|
|
|
+ String text = result.getResult();
|
|
|
+ if (StringUtils.isEmpty(text)) {
|
|
|
+ // 增加redis计数,超过3次失败即为失败
|
|
|
+ String failTimeKey = "adPutTencent:creativeAnalysis:failTime:" + creativeAnalysis.getCreativeId();
|
|
|
+ adOwnRedisUtils.setIncrementIntValue(failTimeKey, 1, 60 * 60L);
|
|
|
+ if (adOwnRedisUtils.getInteger(failTimeKey) > 3) {
|
|
|
+ creativeAnalysis.setStatus(-1);
|
|
|
+ adPutTencentCreativeAnalysisMapper.updateByPrimaryKeySelective(creativeAnalysis);
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ text = text.replaceAll("\\n", "");
|
|
|
+ creativeAnalysis.setTitle(text);
|
|
|
+ creativeAnalysis.setImageUrl(ossImageUrl);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(creativeAnalysis.getTitle()) && StringUtils.isBlank(creativeAnalysis.getCategory())) {
|
|
|
+ // 调用gemini模型提取图片中的文字
|
|
|
+ String prompt = analysisTitleCategoryPrompt.replace("{标题}", creativeAnalysis.getTitle());
|
|
|
+ String result = aigcApiService.gpt("gpt-4o-mini", prompt, null, null);
|
|
|
+ if (StringUtils.isNotEmpty(result)) {
|
|
|
+ String category = result.replaceAll("\\n", "");
|
|
|
+ creativeAnalysis.setCategory(category);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(creativeAnalysis.getCategory()) && Objects.isNull(creativeAnalysis.getMatchVideoId())) {
|
|
|
+ Long videoId = categoryVideoMap.get(creativeAnalysis.getCategory());
|
|
|
+ if (Objects.nonNull(videoId)) {
|
|
|
+ creativeAnalysis.setMatchVideoId(videoId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ creativeAnalysis.setStatus(1);
|
|
|
+ creativeAnalysis.setVideoSource("category");
|
|
|
+ creativeAnalysis.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeAnalysisMapper.updateByPrimaryKeySelective(creativeAnalysis);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("adPutTencentCreativeAnalysisJob error", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ private AdPutTencentComponent getMaxCostComponent(Map<Long, List<AdPutTencentComponentData>> componentsDataMap, Long creativeId) {
|
|
|
+ List<AdPutTencentComponentData> creativeComponentsList = componentsDataMap.get(creativeId);
|
|
|
+ if (CollectionUtil.isEmpty(creativeComponentsList)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<Long> componentIds = creativeComponentsList.stream().map(AdPutTencentComponentData::getComponentId).collect(Collectors.toList());
|
|
|
+ AdPutTencentComponentExample componentExample = new AdPutTencentComponentExample();
|
|
|
+ componentExample.createCriteria().andComponentIdIn(componentIds);
|
|
|
+ List<AdPutTencentComponent> componentList = adPutTencentComponentMapper.selectByExampleWithBLOBs(componentExample);
|
|
|
+ if (CollectionUtil.isEmpty(componentList)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (componentList.size() == 1) {
|
|
|
+ return componentList.get(0);
|
|
|
+ }
|
|
|
+ Map<Long, AdPutTencentComponent> componentIdToComponentMap = componentList.stream().collect(Collectors.toMap(AdPutTencentComponent::getComponentId, Function.identity()));
|
|
|
+ Map<Long, Long> componentIdToCostMap = new HashMap<>();
|
|
|
+ for (AdPutTencentComponentData componentData : creativeComponentsList) {
|
|
|
+ AdPutTencentComponent component = componentIdToComponentMap.get(componentData.getComponentId());
|
|
|
+ if (Objects.isNull(component) || Objects.isNull(component.getImageId())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Long cost = componentIdToCostMap.getOrDefault(componentData.getComponentId(), 0L);
|
|
|
+ cost += componentData.getCost();
|
|
|
+ componentIdToCostMap.put(componentData.getComponentId(), cost);
|
|
|
+ }
|
|
|
+ Long componentId = null;
|
|
|
+ Long maxCost = 0L;
|
|
|
+ for (Map.Entry<Long, Long> longLongEntry : componentIdToCostMap.entrySet()) {
|
|
|
+ if (longLongEntry.getValue() > maxCost) {
|
|
|
+ maxCost = longLongEntry.getValue();
|
|
|
+ componentId = longLongEntry.getKey();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (Objects.isNull(componentId)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ AdPutTencentComponent component = componentIdToComponentMap.get(componentId);
|
|
|
+ if (Objects.isNull(component)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return component;
|
|
|
+ }
|
|
|
+
|
|
|
+ @XxlJob("syncDailyCategoryVideoJob")
|
|
|
+ public ReturnT<String> syncDailyCategoryVideoJob(String param) {
|
|
|
+ String dt = DateUtils.dateToString(new Date(), "yyyy-MM-dd");
|
|
|
+ String sql = "SELECT merge_leve2, head_videoid, head_exposure_cnt, click_cnt, ror, dt\n" +
|
|
|
+ "FROM loghubods.merge_videoid_data_20260226\n" +
|
|
|
+ "WHERE dt = MAX_PT('loghubods.merge_videoid_data_20260226');";
|
|
|
+ List<Record> dataList = OdpsUtil.getOdpsData(sql);
|
|
|
+ if (CollectionUtil.isEmpty(dataList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ List<DailyCategoryVideo> saveList = new ArrayList<>();
|
|
|
+ for (Record record : dataList) {
|
|
|
+ Long videoId = Long.valueOf(record.getString("head_videoid"));
|
|
|
+ String category = record.getString("merge_leve2");
|
|
|
+ if (StringUtils.isBlank(category) || "\\N".equals(category)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ DailyCategoryVideo dailyCategoryVideo = new DailyCategoryVideo();
|
|
|
+ dailyCategoryVideo.setVideoId(videoId);
|
|
|
+ dailyCategoryVideo.setCategory(category);
|
|
|
+ dailyCategoryVideo.setDt(dt);
|
|
|
+ dailyCategoryVideo.setCreateTimestamp(System.currentTimeMillis());
|
|
|
+ saveList.add(dailyCategoryVideo);
|
|
|
+ }
|
|
|
+ if (CollectionUtil.isEmpty(saveList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ adPutTencentExtMapper.deleteDailyCategoryVideo(dt);
|
|
|
+ adPutTencentExtMapper.batchInsertDailyCategoryVideo(saveList);
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ @XxlJob("reAnalysisCreativeVideoJob")
|
|
|
+ public ReturnT<String> reAnalysisCreativeVideoJob(String param) {
|
|
|
+ Integer day = 7;
|
|
|
+ if (StringUtils.isNotBlank(param)) {
|
|
|
+ day = Integer.parseInt(param);
|
|
|
+ }
|
|
|
+ Date startTime = DateUtils.getBeforeDateOfTime(new Date(), day);
|
|
|
+ List<AdPutTencentCreativeAnalysis> analysisList = adPutTencentExtMapper.getReAnalysisCreativeList(startTime);
|
|
|
+ if (CollectionUtil.isEmpty(analysisList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ List<Long> creativeIds = analysisList.stream().map(AdPutTencentCreativeAnalysis::getCreativeId).collect(Collectors.toList());
|
|
|
+ AdPutTencentComponentDataExample componentDataExample = new AdPutTencentComponentDataExample();
|
|
|
+ componentDataExample.createCriteria().andCreativeIdIn(creativeIds).andCreateTimeGreaterThanOrEqualTo(startTime);
|
|
|
+ List<AdPutTencentComponentData> componentsDataList = adPutTencentComponentDataMapper.selectByExample(componentDataExample);
|
|
|
+ Map<Long, List<AdPutTencentComponentData>> componentsDataMap = componentsDataList.stream().collect(Collectors.groupingBy(AdPutTencentComponentData::getCreativeId));
|
|
|
+
|
|
|
+ List<DailyCategoryVideo> dailyCategoryVideoList = adPutTencentExtMapper.getMaxDailyCategoryVideoList();
|
|
|
+ Map<String, Long> categoryVideoMap = dailyCategoryVideoList.stream().collect(Collectors.toMap(DailyCategoryVideo::getCategory, DailyCategoryVideo::getVideoId));
|
|
|
+ for (AdPutTencentCreativeAnalysis creativeAnalysis : analysisList) {
|
|
|
+ AdPutTencentComponent component = getMaxCostComponent(componentsDataMap, creativeAnalysis.getCreativeId());
|
|
|
+ if (Objects.isNull(component)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ String componentId = component.getComponentId().toString();
|
|
|
+ if (StringUtils.isBlank(creativeAnalysis.getTitle())) {
|
|
|
+ // download & upload to oss
|
|
|
+ String fileName = String.format("adPutTencent/image/%s_%s_%d.jpg", creativeAnalysis.getCreativeId(),
|
|
|
+ componentId, System.currentTimeMillis());
|
|
|
+ String ossImageUrl = AliOssFileTool.downloadAndSaveInOSS(fileName, component.getImageUrl(), "image/jpeg");
|
|
|
+ // 调用gemini模型提取图片中的文字
|
|
|
+ String prompt = "识别图片里的文字,直接输出图片里的文字标题,但是不要输出图片里右下角的字,比如“点开看看”“看这里”等,仅输出标题,不要有多余的文字输出";
|
|
|
+ GoogleLLMResult result = aigcApiService.gemini("gemini-2.0-flash", prompt, Arrays.asList(ossImageUrl));
|
|
|
+ String text = result.getResult();
|
|
|
+ if (StringUtils.isEmpty(text)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ text = text.replaceAll("\\n", "");
|
|
|
+ creativeAnalysis.setTitle(text);
|
|
|
+ creativeAnalysis.setImageUrl(ossImageUrl);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(creativeAnalysis.getTitle()) && StringUtils.isBlank(creativeAnalysis.getCategory())) {
|
|
|
+ // 调用gemini模型提取图片中的文字
|
|
|
+ String prompt = analysisTitleCategoryPrompt.replace("{标题}", creativeAnalysis.getTitle());
|
|
|
+ String result = aigcApiService.gpt("gpt-4o-mini", prompt, null, null);
|
|
|
+ if (StringUtils.isNotEmpty(result)) {
|
|
|
+ String category = result.replaceAll("\\n", "");
|
|
|
+ creativeAnalysis.setCategory(category);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(creativeAnalysis.getCategory()) && Objects.isNull(creativeAnalysis.getMatchVideoId())) {
|
|
|
+ Long videoId = categoryVideoMap.get(creativeAnalysis.getCategory());
|
|
|
+ if (Objects.nonNull(videoId)) {
|
|
|
+ creativeAnalysis.setMatchVideoId(videoId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ creativeAnalysis.setStatus(1);
|
|
|
+ creativeAnalysis.setVideoSource("category");
|
|
|
+ creativeAnalysis.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeAnalysisMapper.updateByPrimaryKeySelective(creativeAnalysis);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("adPutTencentCreativeAnalysisJob error", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ @XxlJob("dailyRefreshCreativeVideoJob")
|
|
|
+ public ReturnT<String> dailyRefreshCreativeVideoJob(String param) {
|
|
|
+ // param 可配置视频源: "vector" 使用向量搜索接口, 其他/空 使用原有品类视频源
|
|
|
+ boolean useVectorSource = "vector".equalsIgnoreCase(param);
|
|
|
+
|
|
|
+ AdPutTencentCreativeAnalysisExample example = new AdPutTencentCreativeAnalysisExample();
|
|
|
+ example.createCriteria().andStatusEqualTo(1);
|
|
|
+ List<AdPutTencentCreativeAnalysis> analysisList = adPutTencentCreativeAnalysisMapper.selectByExample(example);
|
|
|
+ if (CollectionUtil.isEmpty(analysisList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ Date startTime = DateUtils.getBeforeDateOfTime(new Date(), dailyRefreshCreativeAnalysisVideoStartDate);
|
|
|
+ List<Long> creativeIds = analysisList.stream().map(AdPutTencentCreativeAnalysis::getCreativeId).collect(Collectors.toList());
|
|
|
+ AdPutTencentComponentDataExample componentDataExample = new AdPutTencentComponentDataExample();
|
|
|
+ componentDataExample.createCriteria().andCreativeIdIn(creativeIds).andCreateTimeGreaterThanOrEqualTo(startTime)
|
|
|
+ .andCostGreaterThan(dailyRefreshCreativeAnalysisVideoMinCost);
|
|
|
+ List<AdPutTencentComponentData> componentsDataList = adPutTencentComponentDataMapper.selectByExample(componentDataExample);
|
|
|
+ Map<Long, List<AdPutTencentComponentData>> componentsDataMap = componentsDataList.stream().collect(Collectors.groupingBy(AdPutTencentComponentData::getCreativeId));
|
|
|
+
|
|
|
+ if (!useVectorSource) {
|
|
|
+ // 原有视频源:按品类匹配每日最优视频
|
|
|
+ List<DailyCategoryVideo> dailyCategoryVideoList = adPutTencentExtMapper.getMaxDailyCategoryVideoList();
|
|
|
+ Map<String, Long> categoryVideoMap = dailyCategoryVideoList.stream().collect(Collectors.toMap(DailyCategoryVideo::getCategory, DailyCategoryVideo::getVideoId));
|
|
|
+ for (AdPutTencentCreativeAnalysis creativeAnalysis : analysisList) {
|
|
|
+ AdPutTencentComponent component = getMaxCostComponent(componentsDataMap, creativeAnalysis.getCreativeId());
|
|
|
+ if (Objects.isNull(component) || StringUtils.isBlank(component.getImageUrl())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(creativeAnalysis.getCategory())) {
|
|
|
+ Long videoId = categoryVideoMap.get(creativeAnalysis.getCategory());
|
|
|
+ if (Objects.nonNull(videoId)) {
|
|
|
+ creativeAnalysis.setMatchVideoId(videoId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ creativeAnalysis.setStatus(1);
|
|
|
+ creativeAnalysis.setVideoSource("category");
|
|
|
+ creativeAnalysis.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeAnalysisMapper.updateByPrimaryKeySelective(creativeAnalysis);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 向量视频源:提交解构任务,redis缓存taskId,最近12小时已提交的创意跳过
|
|
|
+ for (AdPutTencentCreativeAnalysis creativeAnalysis : analysisList) {
|
|
|
+ AdPutTencentComponent component = getMaxCostComponent(componentsDataMap, creativeAnalysis.getCreativeId());
|
|
|
+ if (Objects.isNull(component) || StringUtils.isBlank(component.getImageUrl())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Long creativeId = creativeAnalysis.getCreativeId();
|
|
|
+ // 检查x小时内是否已提交过(替换锁)
|
|
|
+ String replaceLockKey = EnumRedisPrefix.AD_TENCENT_CREATIVE_REPLACE_LOCK.getPrefix()
|
|
|
+ .replace("{creativeId}", creativeId.toString());
|
|
|
+ if (adOwnRedisUtils.contantinsKey(replaceLockKey)) {
|
|
|
+ log.info("dailyRefreshCreativeVideoJob skip, creativeId:{} in 12h lock", creativeId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 检查是否已有处理中的任务
|
|
|
+ String taskIdKey = EnumRedisPrefix.AD_TENCENT_DECONSTRUCT_TASK_ID.getPrefix()
|
|
|
+ .replace("{creativeId}", creativeId.toString());
|
|
|
+ if (adOwnRedisUtils.contantinsKey(taskIdKey)) {
|
|
|
+ log.info("dailyRefreshCreativeVideoJob skip, creativeId:{} already has pending task", creativeId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(creativeAnalysis.getTitle())) {
|
|
|
+ log.info("dailyRefreshCreativeVideoJob skip, creativeId:{} title is blank", creativeId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 构建图片列表
|
|
|
+ List<String> imageList = new ArrayList<>();
|
|
|
+ if (StringUtils.isNotBlank(creativeAnalysis.getImageUrl())) {
|
|
|
+ imageList.add(creativeAnalysis.getImageUrl());
|
|
|
+ } else {
|
|
|
+ // 从component获取图片
|
|
|
+ if (StringUtils.isNotBlank(component.getImageUrl())) {
|
|
|
+ imageList.add(component.getImageUrl());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ String taskId = videoSearchApiService.submitDeconstruct(
|
|
|
+ creativeId.toString(),
|
|
|
+ creativeAnalysis.getTitle(),
|
|
|
+ imageList
|
|
|
+ );
|
|
|
+ if (StringUtils.isNotBlank(taskId)) {
|
|
|
+ // 缓存taskId,保留24小时
|
|
|
+ adOwnRedisUtils.set(taskIdKey, taskId, 24 * 60 * 60L);
|
|
|
+ log.info("dailyRefreshCreativeVideoJob submit deconstruct task, creativeId:{}, taskId:{}", creativeId, taskId);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("dailyRefreshCreativeVideoJob submit deconstruct error, creativeId:{}", creativeId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 扫描处理中的解构任务,获取结果并匹配视频更新 matchVideoId
|
|
|
+ * 建议频率:每5分钟执行一次
|
|
|
+ */
|
|
|
+ @XxlJob("scanDeconstructTaskJob")
|
|
|
+ public ReturnT<String> scanDeconstructTaskJob(String param) {
|
|
|
+ AdPutTencentCreativeAnalysisExample example = new AdPutTencentCreativeAnalysisExample();
|
|
|
+ example.createCriteria().andStatusEqualTo(1);
|
|
|
+ List<AdPutTencentCreativeAnalysis> analysisList = adPutTencentCreativeAnalysisMapper.selectByExample(example);
|
|
|
+ if (CollectionUtil.isEmpty(analysisList)) {
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+ for (AdPutTencentCreativeAnalysis creativeAnalysis : analysisList) {
|
|
|
+ Long creativeId = creativeAnalysis.getCreativeId();
|
|
|
+ String taskIdKey = EnumRedisPrefix.AD_TENCENT_DECONSTRUCT_TASK_ID.getPrefix()
|
|
|
+ .replace("{creativeId}", creativeId.toString());
|
|
|
+ String taskId = adOwnRedisUtils.get(taskIdKey);
|
|
|
+ if (StringUtils.isBlank(taskId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ JSONObject resultData = videoSearchApiService.getDeconstructResult(taskId);
|
|
|
+ if (resultData == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Boolean finished = resultData.getBoolean("finished");
|
|
|
+ Boolean success = resultData.getBoolean("success");
|
|
|
+ if (!Boolean.TRUE.equals(finished)) {
|
|
|
+ // 任务未完成,继续等待
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 任务已完成,无论成功失败都从缓存中移除taskId
|
|
|
+ adOwnRedisUtils.del(taskIdKey);
|
|
|
+ if (!Boolean.TRUE.equals(success)) {
|
|
|
+ log.warn("scanDeconstructTaskJob task failed, creativeId:{}, taskId:{}", creativeId, taskId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 提取选题
|
|
|
+ String topic = videoSearchApiService.extractTopicFromResult(resultData);
|
|
|
+ if (StringUtils.isBlank(topic)) {
|
|
|
+ log.warn("scanDeconstructTaskJob extract topic failed, creativeId:{}, taskId:{}", creativeId, taskId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 匹配视频
|
|
|
+ List<Long> videoIds = videoSearchApiService.matchTopNVideo(topic, 1);
|
|
|
+ if (CollectionUtil.isEmpty(videoIds)) {
|
|
|
+ log.warn("scanDeconstructTaskJob matchTopNVideo empty, creativeId:{}, topic:{}", creativeId, topic);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Long matchedVideoId = videoIds.get(0);
|
|
|
+ creativeAnalysis.setMatchVideoId(matchedVideoId);
|
|
|
+ creativeAnalysis.setStatus(1);
|
|
|
+ creativeAnalysis.setVideoSource("vector");
|
|
|
+ creativeAnalysis.setUpdateTime(new Date());
|
|
|
+ adPutTencentCreativeAnalysisMapper.updateByPrimaryKeySelective(creativeAnalysis);
|
|
|
+ // 24小时内不再重复替换
|
|
|
+ String replaceLockKey = EnumRedisPrefix.AD_TENCENT_CREATIVE_REPLACE_LOCK.getPrefix()
|
|
|
+ .replace("{creativeId}", creativeId.toString());
|
|
|
+ adOwnRedisUtils.set(replaceLockKey, "1", 24 * 60 * 60L);
|
|
|
+ log.info("scanDeconstructTaskJob success, creativeId:{}, matchedVideoId:{}, topic:{}", creativeId, matchedVideoId, topic);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("scanDeconstructTaskJob error, creativeId:{}, taskId:{}", creativeId, taskId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ReturnT.SUCCESS;
|
|
|
+ }
|
|
|
+}
|