|
@@ -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;
|
|
|
+ }
|
|
|
}
|