Parcourir la source

批量2.0添加程序化

zhaoxian il y a 3 ans
Parent
commit
1da3d5f409

+ 2 - 0
jeecg-boot-module-system/src/main/java/cn/com/ctop/kuaishou/modules/batch/mapper/KuaiShouVideoGetMapper.java

@@ -61,4 +61,6 @@ public interface KuaiShouVideoGetMapper extends BaseMapper<KuaiShouVideoGet> {
     List<JSONObject> getVideoListByDate(@Param("startDate") Date startDate,@Param("endDate") Date endDate);
 
     List<String> getDateList();
+
+    List<KuaiShouVideoGet> getVideoListByPhotoIds(@Param("photoIds") JSONArray photoIds,@Param("accountId")Long accountId);
 }

+ 14 - 0
jeecg-boot-module-system/src/main/java/cn/com/ctop/kuaishou/modules/batch/mapper/xml/KuaiShouVideoGetMapper.xml

@@ -404,4 +404,18 @@
             #{videoGet.id}
         </foreach>
     </update>
+
+    <select id="getVideoListByPhotoIds" resultType="cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouVideoGet">
+        SELECT
+            photo_id,
+            cover_url,
+            material_type
+        FROM ctop_kuaishou_video_get
+        WHERE account_id = #{accountId}
+          AND photo_id IN
+        <foreach item="phtotId" index="index" collection="photoIds" open="(" separator="," close=")">
+            #{phtotId}
+        </foreach>
+    </select>
+
 </mapper>

+ 2 - 0
jeecg-boot-module-system/src/main/java/cn/com/ctop/kuaishou/modules/batch/service/IKuaiShouVideoGetService.java

@@ -66,4 +66,6 @@ public interface IKuaiShouVideoGetService extends IService<KuaiShouVideoGet> {
     List<JSONObject> getVideoListByDate(Date startDate, Date endDate);
 
     List<String> getDateList();
+
+    List<KuaiShouVideoGet> getVideoListByPhotoIds(JSONArray photoIds,Long accountId);
 }

+ 224 - 23
jeecg-boot-module-system/src/main/java/cn/com/ctop/kuaishou/modules/batch/service/impl/KuaiShouGroupTemplateServiceImpl.java

@@ -3,20 +3,35 @@ package cn.com.ctop.kuaishou.modules.batch.service.impl;
 import cn.com.ctop.common.module.entity.CtopOauthToken;
 import cn.com.ctop.common.module.service.ICtopOauthTokenService;
 import cn.com.ctop.common.module.utils.Check;
+import cn.com.ctop.common.module.utils.HttpUtils;
+import cn.com.ctop.common.module.utils.KuaishouInterfaceConstant;
+import cn.com.ctop.common.module.utils.PropertiesUtils;
+import cn.com.ctop.kuaishou.modules.ai.entity.AiKuaishouAccountAutoVideo;
+import cn.com.ctop.kuaishou.modules.ai.service.IKuaishouLandpagePackageService;
 import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouGroupTemplate;
 import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouImageGet;
+import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouVideoGet;
 import cn.com.ctop.kuaishou.modules.batch.entity.KuaishouTemplateTarget;
 import cn.com.ctop.kuaishou.modules.batch.mapper.KuaiShouGroupTemplateMapper;
-import cn.com.ctop.kuaishou.modules.batch.service.*;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouGroupTemplateService;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouImageGetService;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouMaterialUploadService;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouVideoGetService;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouInterfaceService;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouTemplateTargetService;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -44,7 +59,8 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
     private IKuaiShouMaterialUploadService uploadService;
     @Autowired
     private IKuaishouTemplateTargetService templateTargetService;
-
+    @Autowired
+    private IKuaiShouVideoGetService kuaiShouVideoGetService;
     static ExecutorService executorService = Executors.newFixedThreadPool(5);
 
     /**
@@ -73,19 +89,22 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
             throw new Exception("请选择需要创建的视频");
         }
 
+
         Integer createType = requestJson.getInteger("createType"); // 创建类型 0 单品 1 混搭
-        if (Check.isNull(createType)) {
-            throw new Exception("请选择创意创建方式混搭、单品");
-        }
+        Integer unitType = requestJson.getInteger("unitType"); // 7程序化。4自定义
+        if (unitType == 4) {
+            if (Check.isNull(createType)) {
+                throw new Exception("请选择创意创建方式混搭、单品");
+            }
 
-        if (createType == 0 && createCount != photoArr.size()) {
-            throw new Exception("单品视频数量必须和创建数量保持一致");
-        }
+            if (createType == 0 && createCount != photoArr.size()) {
+                throw new Exception("单品视频数量必须和创建数量保持一致");
+            }
 
-        if (createType == 1 && createCount * 15 != photoArr.size()) {
-            throw new Exception("混搭视频数量必须和创建数量保持倍数关系");
+            if (createType == 1 && createCount * 15 != photoArr.size()) {
+                throw new Exception("混搭视频数量必须和创建数量保持倍数关系");
+            }
         }
-
         JSONObject returnJson = new JSONObject();
         String userId = requestJson.getString("userId");
         String unitName = requestJson.getString("unitName");
@@ -131,10 +150,10 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
         for (int i = 0; i < createCount; i++) {
             KuaiShouGroupTemplate template = new KuaiShouGroupTemplate();
             template.setCreateType(createType);
-            if (createType == 0) { // 创建方式为单品
+            if (!Check.isNull(createType) && createType == 0) { // 创建方式为单品
                 Long photoId = photoArr.getLong(i);
                 template.setPhotoId(photoId);
-            } else if (createType == 1) { // 创建方式为混搭
+            } else if (!Check.isNull(createType) && createType == 1) { // 创建方式为混搭
                 JSONArray photoIds = getPhotoIds(photoArr, i);
                 if (Check.isNull(photoIds)) {
                     log.error("根据下标未获取到详细信息");
@@ -365,9 +384,6 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
         if (!Check.isNull(template.getDeepConversionBid())) {
             createUnitJson.put("deep_conversion_bid", template.getDeepConversionBid()); //深度转化目标出价
         }
-        if (!Check.isNull(template.getUnitType())) {
-            createUnitJson.put("unit_type", template.getUnitType()); //创意制作方式
-        }
         if (!Check.isNull(template.getBeginTime())) {
             createUnitJson.put("begin_time", template.getBeginTime()); //投放开始时间
         }
@@ -402,6 +418,10 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
         if (!Check.isNull(template.getSpeed())) {
             createUnitJson.put("speed", template.getSpeed()); // 投放方式
         }
+        if (!Check.isNull(template.getUnitType())) {
+            createUnitJson.put("unit_type", template.getUnitType()); //创意制作方式
+        }
+
         Map<String, Object> groupMap = iKuaishouInterfaceService.adUnitCreate(token.getAccessToken(), accountId, createUnitJson, 1);
         updateTemplate = new KuaiShouGroupTemplate();
         updateTemplate.setId(template.getId());
@@ -410,13 +430,23 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
             updateTemplate.setTaskStatus(2);
             Long unit = (Long) groupMap.get("unitId");
             updateTemplate.setUnitId((unit));
-            Thread thread = new Thread() {
-                @Override
-                public void run() {
-                    createCreative(token.getAccessToken(), unit, template);
-                }
-            };
-            thread.start();
+            if (template.getUnitType() == 4) {
+                Thread thread = new Thread() {
+                    @Override
+                    public void run() {
+                        createCreative(token.getAccessToken(), unit, template);
+                    }
+                };
+                thread.start();
+            } else {
+                Thread thread = new Thread() {
+                    @Override
+                    public void run() {
+                        createProgramCreative(token.getAccessToken(), unit, template);
+                    }
+                };
+                thread.start();
+            }
         } else {
             updateTemplate.setTaskStatus(3);
             updateTemplate.setReviewDetail((String) groupMap.get("message"));
@@ -712,6 +742,156 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
     }
 
 
+    private void createProgramCreative(String accessToken, Long unitId, KuaiShouGroupTemplate template) {
+        KuaiShouGroupTemplate updateTemplate = new KuaiShouGroupTemplate();
+        updateTemplate.setId(template.getId());
+        updateTemplate.setCreativeStatus(1);
+        updateTemplate.setCreativeReviewDetail("创意创建中");
+        updateTemplate.setUnitId(unitId);
+        this.updateById(updateTemplate);
+        JSONObject createJson = new JSONObject();
+        Long accountId = template.getAccountId();
+        createJson.put("advertiser_id", accountId);
+        createJson.put("unit_id", unitId);
+        createJson.put("package_name", template.getCreativeName());
+
+        JSONArray photoIds = JSONArray.parseArray(template.getPhotoIds());
+        if (Check.isNull(photoIds)) {
+            updateTemplate.setCreativeStatus(3);
+            updateTemplate.setCreativeReviewDetail("未获取到PhotoIds");
+            this.updateById(updateTemplate);
+            return;
+        }
+        //素材列表
+        List<KuaiShouVideoGet> videos = kuaiShouVideoGetService.getVideoListByPhotoIds(photoIds, accountId);
+        if (Check.isNull(videos) || videos.isEmpty()) {
+            updateTemplate.setCreativeStatus(3);
+            updateTemplate.setCreativeReviewDetail("未获取到素材信息");
+            this.updateById(updateTemplate);
+            return;
+        }
+        // 程序化视频数
+        Integer imageCount = template.getImageCount();
+        if (imageCount < 3) {
+            log.error("视频数小于3个,不执行创建");
+            return;
+        }
+
+        //落地页 ID
+        if (!Check.isNull(template.getSiteId()) && !"-1".equals(template.getSiteId())) {
+            createJson.put("site_id", template.getSiteId());
+        }
+        //行动号召按钮
+        if (!Check.isNull(template.getActionBarText())) {
+            createJson.put("action_bar", template.getActionBarText());
+        }
+        //第三方点击检测链接
+        if (!Check.isNull(template.getClickTrackUrl())) {
+            createJson.put("click_url", template.getClickTrackUrl());
+        }
+        //第三方 ActionBar 点击监控链接
+        if (!Check.isNull(template.getActionbarClickUrl())) {
+            createJson.put("actionbar_click_url", template.getActionbarClickUrl());
+        }
+        //创意分类 与创意标签同时传或同时不传
+        if (!Check.isNull(template.getCreativeCategory())) {
+            createJson.put("creative_category", template.getCreativeCategory());
+            createJson.put("creative_tag", JSONArray.parseArray(template.getCreativeTag()));
+        }
+        //作品广告语
+        createJson.put("captions", getCaptions(template.getDescription()));
+
+        List<List<KuaiShouVideoGet>> splitVideos = Lists.newArrayList(Lists.partition(videos, imageCount));
+        for (List<KuaiShouVideoGet> splitVideo : splitVideos) {
+            JSONArray photoList = new JSONArray();
+            for (KuaiShouVideoGet video : splitVideo) {
+                JSONObject photo = new JSONObject();
+                photo.put("photo_id", video.getPhotoId());//视频 ID
+                photo.put("cover_image_token", null);//封面图片 token,通过上传图片接口获得,不传值则直接使用视频的首帧作为封面图片
+                photo.put("creative_material_type", video.getMaterialType());//1:竖版视频 2:横版视频
+                photoList.add(photo);
+            }
+            createJson.put("photo_list", photoList);
+            Map<String, Object> creativeMap = this.createProgramCreatives(accountId, accessToken, createJson, 1);
+            Integer code = (Integer) creativeMap.get("code");
+            if (code == 0) {
+                updateTemplate.setCreativeStatus(2);
+                updateTemplate.setCreativeReviewDetail("创建程序化2.0创意成功");
+            } else {
+                updateTemplate.setCreativeStatus(3);
+                updateTemplate.setCreativeReviewDetail((String) creativeMap.get("message"));
+            }
+            this.updateById(updateTemplate);
+        }
+    }
+
+    /**
+     * 创建程序化创意
+     */
+    private Map<String, Object> createProgramCreatives(Long accountId, String token, JSONObject creativeParams, int count) {
+        Map<String, Object> returnMap = new HashMap<>();
+        try {
+            Map<String, String> headers = new HashMap<>();
+            headers.put("Content-Type", "application/json");
+            headers.put("Access-Token", token);
+            String url = PropertiesUtils.getConfig("kuaishou_api_url") + KuaishouInterfaceConstant.PROGRAM_CREATE;
+            String result = HttpUtils.kuaiShouhttpPostRequest(url, creativeParams.toJSONString(), headers);
+            JSONObject resultJson = JSON.parseObject(result);
+            if (Check.isNull(resultJson)) {
+                log.error("程序化创意创意异常:api接口返回为空");
+                returnMap.put("code", -1);
+                returnMap.put("message", "程序化创意创意异常:api接口返回为空");
+                returnMap.put("success", false);
+                return returnMap;
+            }
+            Integer code = resultJson.getInteger("code");
+            String message = resultJson.getString("message");
+            Long unitId = creativeParams.getLong("unit_id");
+            if (code == 0) {
+                createLandPageAndUnit(creativeParams, resultJson.getJSONObject("data"));
+                returnMap.put("code", 0);
+                returnMap.put("message", "success");
+                returnMap.put("success", true);
+            } else {
+                log.error("批量2.0创建程序化创意失败,入参:{},返回结果:{}", creativeParams.toString(), resultJson.toString());
+                if ("系统错误".equals(message) && count <= 3) {
+                    log.info("第{}次重新创建程序化创意", count);
+                    //系统错误,则重新执行
+                    return createProgramCreatives(accountId, token, creativeParams, count + 1);
+                }
+                returnMap.put("code", -1);
+                returnMap.put("message", resultJson.getString("message"));
+                returnMap.put("success", false);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("执行创建程序化创意异常", e);
+            returnMap.put("code", -1);
+            returnMap.put("message", "执行创建程序化创意异常");
+            returnMap.put("success", false);
+        }
+        return returnMap;
+    }
+
+    /**
+     * 绑定落地页与广告组、创意的关系
+     */
+    @Autowired
+    private IKuaishouLandpagePackageService landpagePackageService;
+
+    private void createLandPageAndUnit(JSONObject programJson, JSONObject data) {
+        if (!Check.isNull(data) && !Check.isNull(programJson.getLong("site_id"))) {
+            Thread thread = new Thread() {
+                @Override
+                public void run() {
+                    landpagePackageService.createLandPageAndUnit(programJson.getLong("site_id"), data.getLong("creative_id"), programJson.getLong("unit_id"), programJson.getLong("advertiser_id"));
+                }
+            };
+            thread.start();
+        }
+    }
+
+
     private String getImageToken(String md5, Long accountId, String accessToken, String url) {
 
         String imageToken = null;
@@ -730,4 +910,25 @@ public class KuaiShouGroupTemplateServiceImpl extends ServiceImpl<KuaiShouGroupT
         return imageToken;
 
     }
+
+
+    /**
+     * 获取程序化广告语
+     */
+    private JSONArray getCaptions(String description) {
+        JSONArray jsonArray = JSONArray.parseArray(description);
+        if (jsonArray.size() <= 3) {
+            return jsonArray;
+        }
+        //重置顺序
+        Collections.shuffle(jsonArray);
+        JSONArray captions = new JSONArray();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            captions.add(jsonArray.getString(i));
+            if (captions.size() == 3) {
+                break;
+            }
+        }
+        return captions;
+    }
 }

+ 5 - 0
jeecg-boot-module-system/src/main/java/cn/com/ctop/kuaishou/modules/batch/service/impl/KuaiShouVideoGetServiceImpl.java

@@ -359,4 +359,9 @@ public class KuaiShouVideoGetServiceImpl extends ServiceImpl<KuaiShouVideoGetMap
     public List<String> getDateList() {
         return videoGetMapper.getDateList();
     }
+
+    @Override
+    public List<KuaiShouVideoGet> getVideoListByPhotoIds(JSONArray photoIds,Long accountId) {
+        return videoGetMapper.getVideoListByPhotoIds(photoIds, accountId);
+    }
 }