package com.backendsys.service.SDKService.SDKTencent; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.backendsys.aspect.HttpRequestAspect; import com.backendsys.entity.Ai.Aiivh.*; import com.backendsys.entity.Ai.Aiivh.AiivhAsset.AiivhAssetQuotaStatisticsDTO; import com.backendsys.entity.Ai.Aiivh.AiivhMakeBroadcastTask.SpeechParamDTO; import com.backendsys.entity.Ai.Aiivh.AiivhMakeBroadcastTask.VideoParamAnchorParamDTO; import com.backendsys.entity.Ai.Aiivh.AiivhMakeBroadcastTask.VideoParamDTO; import com.backendsys.entity.Ai.Aiivh.AiivhMakeBroadcastTask.VideoParamLogoParamDTO; import com.backendsys.entity.Tencent.*; import com.backendsys.enums.IvhQuotaActiveEvent; import com.backendsys.exception.CustException; import com.backendsys.mapper.Ai.Aiivh.AiivhQuotaHistoryMapper; import com.backendsys.mapper.Ai.Aiivh.AiivhQuotaMapper; import com.backendsys.service.Ai.Aiivh.AiivhAssetService; import com.backendsys.service.Ai.Aiivh.AiivhMakeVirtualmanTaskService; import com.backendsys.utils.ListUtil; import com.backendsys.utils.MapUtil; import org.redisson.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriComponentsBuilder; import java.lang.reflect.Field; import java.net.URI; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Service public class SDKTencentAiVirtualmanServiceImpl implements SDKTencentAiVirtualmanService { @Lazy @Autowired RedissonClient redissonClient; @Autowired private HttpRequestAspect httpRequestAspect; @Autowired private SDKTencentService sdkTencentService; @Autowired private AiivhMakeVirtualmanTaskService aiivhMakeVirtualmanTaskService; @Autowired private AiivhAssetService aiivhAssetService; @Autowired private AiivhQuotaMapper aiivhQuotaMapper; @Autowired private AiivhQuotaHistoryMapper aiivhQuotaHistoryMapper; @Value("${tencent.ivh.app-key}") private String appKey; @Value("${tencent.ivh.access-token}") private String accessToken; @Value("${tencent.ivh.empty-app-key}") private String emptyAppKey; @Value("${tencent.ivh.empty-access-token}") private String emptyAccessToken; /** * [腾讯-数智人] 初始化 定制数智人列表 (使用公司账号) */ @Transactional public Map initCustomVirtualman(Integer pageIndex, Integer pageSize) { Map payload = new HashMap<>(); payload.put("VirtualmanTypeCode", "small_sample_2d"); // payload.put("AnchorCodes", "Array of [string]"); payload.put("PageIndex", pageIndex); payload.put("PageSize", pageSize); Map resultMap = Collections.singletonMap("Payload", payload); String bodyData = JSONUtil.toJsonStr(resultMap); // -- Http Request -------------------------------------------- /** * 这里使用我自己的空白密钥,因为只有未创建自定义形象的账号,才能返回全部形象 */ Map signature = sdkTencentService.getSignature(appKey, accessToken); // 获得 Signature 签名 String url = "https://gw.tvs.qq.com/v2/ivh/crmserver/customerassetservice/describesmallsampleimage"; URI uriWithParams = UriComponentsBuilder.fromUriString(url) .queryParam("appkey", signature.get("appkey")) .queryParam("signature", "{signature}") .queryParam("timestamp", signature.get("timestamp")) .build(signature.get("signature")); // Http 远程调用 Map resp = WebClient.create() .method(HttpMethod.POST) .uri(uriWithParams) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(bodyData.toString()) .retrieve().bodyToMono(new ParameterizedTypeReference>() { }) .block(); return resp; } /** * [腾讯-数智人] 初始化公共数智人列表 (使用空白账号) * 注:有效期:2024/03/25-2024/04/08 过期后能否继续查询? */ @Transactional public Map initPublicVirtualman(Integer pageIndex, Integer pageSize) { Map payload = new HashMap<>(); payload.put("VirtualmanTypeCode", "small_sample_2d"); // payload.put("AnchorCodes", "Array of [string]"); payload.put("PageIndex", pageIndex); payload.put("PageSize", pageSize); Map resultMap = Collections.singletonMap("Payload", payload); String bodyData = JSONUtil.toJsonStr(resultMap); // -- Http Request -------------------------------------------- /** * 这里使用我自己的空白密钥,因为只有未创建自定义形象的账号,才能返回全部形象 */ Map signature = sdkTencentService.getSignature(emptyAppKey, emptyAccessToken); // 获得 Signature 签名 String url = "https://gw.tvs.qq.com/v2/ivh/crmserver/customerassetservice/describesmallsampleimage"; URI uriWithParams = UriComponentsBuilder.fromUriString(url) .queryParam("appkey", signature.get("appkey")) .queryParam("signature", "{signature}") .queryParam("timestamp", signature.get("timestamp")) .build(signature.get("signature")); // Http 远程调用 Map resp = WebClient.create() .method(HttpMethod.POST) .uri(uriWithParams) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(bodyData.toString()) .retrieve().bodyToMono(new ParameterizedTypeReference>() { }) .block(); return resp; } /** * 基于实体类,将 anchor_name 转换为 AnchorName (将下划线转为大驼峰) * * Map resultMap = new HashMap<>(); * convertObjectToMap(tencentCustomserviceDTO, resultMap); * System.out.println(resultMap); */ public static void convertObjectToMap(Object obj, Map resultMap) throws IllegalAccessException { Class clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object value = field.get(obj); String fieldName = field.getName(); String convertedFieldName = StrUtil.upperFirst(StrUtil.toCamelCase(fieldName)); if (value != null) { /** * 注意:需要手动填写实体类 */ if (value instanceof List) { // 如果值是列表类型,则遍历列表中的每个对象 List list = (List)value; Map nestedMap = new HashMap<>(); List> nestedList = new ArrayList<>(); for (Object item : list) { Map itemMap = new HashMap<>(); convertObjectToMap(item, itemMap); nestedList.add(itemMap); } resultMap.put(convertedFieldName, nestedList); } else if (value.getClass().isAssignableFrom(VideoParamAnchorParamDTO.class) || value.getClass().isAssignableFrom(VideoParamLogoParamDTO.class) || value.getClass().isAssignableFrom(VideoParamDTO.class) || value.getClass().isAssignableFrom(SpeechParamDTO.class) || value.getClass().isAssignableFrom(TencentCustomservicePayloadDTO.class) || value.getClass().isAssignableFrom(TencentCustomserviceConfirmPlayloadDTO.class) || value.getClass().isAssignableFrom(TencentCustomserviceHeaderDTO.class) || value.getClass().isAssignableFrom(Payload.class)) { // If the value is a nested object, recursively convert it to map Map nestedMap = new HashMap<>(); convertObjectToMap(value, nestedMap); // fieldName = field.getName(); convertedFieldName = StrUtil.upperFirst(StrUtil.toCamelCase(fieldName)); resultMap.put(convertedFieldName, nestedMap); } else { fieldName = field.getName(); convertedFieldName = StrUtil.upperFirst(StrUtil.toCamelCase(fieldName)); resultMap.put(convertedFieldName, value); } } } } private String getAnchorNameView(String anchor_name) { LocalDateTime now = LocalDateTime.now(); String timestamp = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); return anchor_name + "_" + timestamp; } /** * [腾讯-数智人] 创建形象/音色定制任务 */ @Transactional public Map makeVirtualTask(TencentCustomserviceDTO tencentCustomserviceDTO) { RLock lock = redissonClient.getLock("makeVirtualTask"); try { lock.tryLock(3, TimeUnit.SECONDS); // 参数校验: // - IdentityWrittenCosUrl 二选一或二者都传 // - IdentityCosUrl 二选一或二者都传 // 基于实体类,将 anchor_name 转换为 AnchorName (将下划线转为大驼峰) Map resultMap = new HashMap<>(); // 生成: AnchorName 数智人名称_时间戳 (使接口值唯一,本地数据不唯一) // - anchor_name 唯一 // - anchor_name_view 不唯一 TencentCustomservicePayloadDTO payload = tencentCustomserviceDTO.getPayload(); payload.setAnchor_name_view(getAnchorNameView(payload.getAnchor_name())); tencentCustomserviceDTO.setPayload(payload); convertObjectToMap(tencentCustomserviceDTO, resultMap); String bodyData = JSONUtil.toJsonStr(resultMap); // System.out.println("resultMap:"); // System.out.println(resultMap); // System.out.println("-----------------------------------------"); // System.out.println("bodyData:"); // System.out.println(bodyData); // System.out.println("-----------------------------------------"); // -- Http Request -------------------------------------------- Map signature = sdkTencentService.getSignature(appKey, accessToken); // 获得 Signature 签名 String url = "https://gw.tvs.qq.com/v2/ivh/assetmanager/customservice/make"; URI uriWithParams = UriComponentsBuilder.fromUriString(url) .queryParam("appkey", signature.get("appkey")) .queryParam("signature", "{signature}") .queryParam("timestamp", signature.get("timestamp")) .build(signature.get("signature")); // Http 远程调用 Map resp = WebClient.create() .method(HttpMethod.POST) .uri(uriWithParams) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(bodyData) .retrieve().bodyToMono(new ParameterizedTypeReference>() { }) .block(); System.out.println(resp); //// 临时数据 (模拟成功) //Map tempPayload = new LinkedHashMap<>(); //String uuid = String.valueOf(UUID.randomUUID()); //tempPayload.put("TaskId", uuid); //resp.put("Payload", tempPayload); /** * 创建任务 (远程) */ // 判断 任务是否创建成功 (是,则创建数据库记录) Integer respHeaderCode = (Integer) MapUtil.get(resp, "Header.Code"); if (respHeaderCode == 0) { /** * 创建任务 (本地) */ TencentCustomservicePayloadDTO tencentCustomservicePayloadDTO = tencentCustomserviceDTO.getPayload(); String make_type = tencentCustomservicePayloadDTO.getMake_type(); // -- [Post] 创建数智人任务 -------------------------------------------------------- AiPersonDTO aiPersonDTO = new AiPersonDTO(); // [查询] 自身 UserId Long user_id = httpRequestAspect.getUserId(); aiPersonDTO.setUser_id(user_id); // aiPersonDTO.setRequest_id((String) MapUtil.get(resp, "Header.RequestID")); aiPersonDTO.setTask_id((String) MapUtil.get(resp, "Payload.TaskId")); aiPersonDTO.setAnchor_name(tencentCustomservicePayloadDTO.getAnchor_name_view()); aiPersonDTO.setAnchor_name_view(tencentCustomservicePayloadDTO.getAnchor_name()); aiPersonDTO.setMake_type(make_type); aiPersonDTO.setIdentity_cos_url(tencentCustomservicePayloadDTO.getIdentity_cos_url()); aiPersonDTO.setIdentity_written_cos_url(tencentCustomservicePayloadDTO.getIdentity_written_cos_url()); aiPersonDTO.setMaterial_cos_url(tencentCustomservicePayloadDTO.getMaterial_cos_url()); aiPersonDTO.setIs_remove_background(tencentCustomservicePayloadDTO.getIs_remove_background()); aiPersonDTO.setSex_type(tencentCustomservicePayloadDTO.getSex_type()); aiPersonDTO.setNotes(tencentCustomservicePayloadDTO.getNotes()); aiPersonDTO.setText_driver(tencentCustomservicePayloadDTO.getText_driver()); aiPersonDTO.setVoice_driver_cos_file(tencentCustomservicePayloadDTO.getVoice_driver_cos_file()); aiivhMakeVirtualmanTaskService.insertAiivhMakeVirtualmanTask(aiPersonDTO); /** * 创建任务之后,此时是 { "Stage": EXAMINE } 状态,还未生成任务, * 大概1分钟内才会更变状态 * * 创建任务成功后,创建一个临时 [形象] 记录,主要是记录 user_id 和 anchor_name 字段 * 等待用户访问查询详情接口之后,再更新 [形象详情] */ if(make_type.equals("IMAGE_GENERAL")) { // 定制形象 (创建临时记录) AiivhAnchorDTO aiivhAnchorDTO = new AiivhAnchorDTO(); aiivhAnchorDTO.setAnchor_name(tencentCustomservicePayloadDTO.getAnchor_name_view()); aiivhAnchorDTO.setAnchor_name_view(tencentCustomservicePayloadDTO.getAnchor_name()); aiivhAnchorDTO.setUser_id(user_id); aiivhMakeVirtualmanTaskService.insertAiivhAnchorCustom(aiivhAnchorDTO); } if(make_type.equals("VOICE")) { // 定制音色 (创建临时记录) AiPersonTimbreCustomDTO aiPersonTimbreCustomDTO = new AiPersonTimbreCustomDTO(); aiPersonTimbreCustomDTO.setTimbre_name(tencentCustomservicePayloadDTO.getAnchor_name_view()); aiPersonTimbreCustomDTO.setTimbre_name_view(tencentCustomservicePayloadDTO.getAnchor_name()); aiPersonTimbreCustomDTO.setUser_id(user_id); aiivhMakeVirtualmanTaskService.insertAiPersoneTimbreCustom(aiPersonTimbreCustomDTO); } } return resp; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } } /** * [腾讯-数智人] 创建定制形象任务 (未提交远程) */ @Transactional public Map insertVirtualmanTask(TencentCustomserviceDTO tencentCustomserviceDTO) { TencentCustomservicePayloadDTO tencentCustomservicePayloadDTO = tencentCustomserviceDTO.getPayload(); // -- 将带 Payload 的参数进行格式化 -------------------------------------------------------- AiPersonDTO aiPersonDTO = new AiPersonDTO(); // [查询] 自身 UserId Long user_id = httpRequestAspect.getUserId(); aiPersonDTO.setUser_id(user_id); // // aiPersonDTO.setRequest_id((String) MapUtil.get(resp, "Header.RequestID")); // aiPersonDTO.setTask_id((String) MapUtil.get(resp, "Payload.TaskId")); String anchor_name = tencentCustomservicePayloadDTO.getAnchor_name(); aiPersonDTO.setAnchor_name(getAnchorNameView(anchor_name)); aiPersonDTO.setAnchor_name_view(anchor_name); aiPersonDTO.setQuota_code(tencentCustomserviceDTO.getQueue_code()); aiPersonDTO.setMake_type(tencentCustomserviceDTO.getPayload().getMake_type()); aiPersonDTO.setIdentity_cos_url(tencentCustomservicePayloadDTO.getIdentity_cos_url()); aiPersonDTO.setIdentity_written_cos_url(tencentCustomservicePayloadDTO.getIdentity_written_cos_url()); aiPersonDTO.setMaterial_cos_url(tencentCustomservicePayloadDTO.getMaterial_cos_url()); aiPersonDTO.setIs_remove_background(tencentCustomservicePayloadDTO.getIs_remove_background()); aiPersonDTO.setSex_type(tencentCustomservicePayloadDTO.getSex_type()); aiPersonDTO.setNotes(tencentCustomservicePayloadDTO.getNotes()); aiPersonDTO.setText_driver(tencentCustomservicePayloadDTO.getText_driver()); aiPersonDTO.setVoice_driver_cos_file(tencentCustomservicePayloadDTO.getVoice_driver_cos_file()); aiPersonDTO.setTask_status("AUDIT"); return aiivhMakeVirtualmanTaskService.insertAiivhMakeVirtualmanTask(aiPersonDTO); } /* // 排队机制(定时任务?) // 1.先查询排队表,如果为空,则提交,同时返回任务ID;如果前面有人,则排队,返回排队人数 // // 2.数据插入定制数据人列表 (不执行),同时插入排队表 (包含提交的数据) // 4.用定时任务查询未完成记录 (查询成功或失败,则将排队表中的记录去除;同时将下一个任务自动提交) // 这一步还不用排队,要等运营人员点提交才有 // // -- 使用 Redisson 排队 ----------------------------------------------------------------- // RList rList = redissonClient.getList("makeVirtualTaskQueue"); // tencentCustomserviceDTO.setQueue_code(CommonUtil.generateUniqueRandomOrderCode("QUE")); // String jsonString = JSONUtil.toJsonStr(tencentCustomserviceDTO); // // 入队 // rList.add(jsonString); */ /** * [方法] 查询我的配额,并获得有效(类型匹配,状态可用,未过期),最近临期的那一条配额 */ private Map getEffectiveQuota(String quotaType, String makeType) { // [Get] 查询我的配额 AiivhQuotaDTO aiivhQuotaDTO = new AiivhQuotaDTO(); aiivhQuotaDTO.setUser_id(httpRequestAspect.getUserId()); List> myQuota = aiivhQuotaMapper.queryAiivhQuotaList(aiivhQuotaDTO); LocalDateTime now = LocalDateTime.now(); String finalQuotaType = quotaType; myQuota = myQuota.stream().filter(map -> { String qType = (String) map.get("quota_type"); // 配额类型 (Anchor|Timbre) Integer qStatus = (Integer) map.get("quota_status"); // 配额状态 (1未使用|2使用中|3已使用) String expireDateString = (String) map.get("expire_date"); // 过期时间 (对比当前时间) LocalDateTime expireDate = LocalDateTime.parse(expireDateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); return (finalQuotaType.equals(qType)) && qStatus == 1 && !now.isAfter(expireDate); }).sorted(Comparator.comparing(map -> { String expireDateString = map.get("expire_date").toString(); // 按过期时间排序 (最早创建在最前面) return LocalDateTime.parse(expireDateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); })).collect(Collectors.toList()); if (myQuota.size() == 0) { throw new CustException("(" + makeType + ") 配额不足"); } else { // 获得最近临期的那一条配额 Map targetQuota = myQuota.get(0); return targetQuota; } } /** * 在上面定制的基础上增加排队机制 */ @Transactional public Map makeVirtualTaskQueue(TencentCustomserviceDTO tencentCustomserviceDTO) { RLock lock = redissonClient.getLock("makeVirtualTask"); try { lock.tryLock(3, TimeUnit.SECONDS); // [Get] 查询我的配额数量一览 AiivhAssetQuotaStatisticsDTO aiivhAssetQuotaStatisticsDTO = aiivhAssetService.getMyOverview(); // 判断配额是否足够 Long quota_balance = null; String makeType = tencentCustomserviceDTO.getPayload().getMake_type(); String quotaType = null; String activeType = null, activeTypeDescription = null; // [定制视频] 2D小样本-标准版(通用口型)形象定制 if (makeType.equals("IMAGE_GENERAL")) { quota_balance = aiivhAssetQuotaStatisticsDTO.getAnchor_free_quota(); quotaType = "Anchor"; activeType = IvhQuotaActiveEvent.MAKE_ANCHOR.getCode(); activeTypeDescription = IvhQuotaActiveEvent.MAKE_ANCHOR.getDescription(); } // [定制音色] 2D小样本声音定制 if (makeType.equals("VOICE")) { quota_balance = aiivhAssetQuotaStatisticsDTO.getTimbre_free_quota(); quotaType = "Timbre"; activeType = IvhQuotaActiveEvent.MAKE_TIMBRE.getCode(); activeTypeDescription = IvhQuotaActiveEvent.MAKE_TIMBRE.getDescription(); } if (quota_balance <= 0) { throw new CustException("(" + makeType + ") 配额不足"); } else { // -- 1.查询我的配额,并获得有效(类型匹配,状态可用,未过期),最近临期的那一条配额 ----------------------------- Map targetQuota = getEffectiveQuota(quotaType, makeType); String quotaCode = (String) targetQuota.get("quota_code"); // -- 2.修改配额状态: 2使用中 ------------------------------------------------------------------------ AiivhQuotaDTO aiivhQuotaDTO = new AiivhQuotaDTO(); aiivhQuotaDTO.setQuota_code(quotaCode); aiivhQuotaDTO.setQuota_status(2); aiivhQuotaMapper.updateAiivhQuota(aiivhQuotaDTO); // -- 3.记录 ai_ivh_quota_history 操作 ------------------------------------------------------------ List list = new ArrayList<>(); AiivhQuotaHistoryDTO aiivhQuotaHistoryDTO = new AiivhQuotaHistoryDTO(); aiivhQuotaHistoryDTO.setUser_id(httpRequestAspect.getUserId()); aiivhQuotaHistoryDTO.setActivity_type(activeType); aiivhQuotaHistoryDTO.setActivity_type_description(activeTypeDescription); aiivhQuotaHistoryDTO.setQuota_type(quotaType); aiivhQuotaHistoryDTO.setQuota_adjustment(-1); list.add(aiivhQuotaHistoryDTO); aiivhQuotaHistoryMapper.insertAiivhQuotaHistoryBatch(list); // 创建定制形象任务 (未提交) tencentCustomserviceDTO.setQueue_code(quotaCode); return insertVirtualmanTask(tencentCustomserviceDTO); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } } /** * 发起任务 (填写 腾讯订单、备注,同时发起任务) */ @Transactional public Map launchVirtualTaskQueue(VirtualmanLaunchDTO virtualmanLaunchDTO) { // 1.获得任务详情 AiPersonDTO aiPersonDTO = new AiPersonDTO(); aiPersonDTO.setQuota_code(virtualmanLaunchDTO.getQuota_code()); Map taskDetail = aiivhMakeVirtualmanTaskService.queryAiivhMakeVirtualmanTaskDetail(aiPersonDTO); // 2.发起任务 TencentCustomserviceDTO tencentCustomserviceDTO = new TencentCustomserviceDTO(); TencentCustomservicePayloadDTO payloadDTO = new TencentCustomservicePayloadDTO(); payloadDTO.setAnchor_name((String) taskDetail.get("anchor_name")); payloadDTO.setMake_type((String) taskDetail.get("make_type")); payloadDTO.setIdentity_cos_url((String) taskDetail.get("identity_cos_url")); payloadDTO.setIdentity_written_cos_url((String) taskDetail.get("identity_written_cos_url")); payloadDTO.setMaterial_cos_url((String) taskDetail.get("material_cos_url")); payloadDTO.setIs_remove_background((Integer) taskDetail.get("is_remove_background")); payloadDTO.setSex_type((String) taskDetail.get("sex_type")); payloadDTO.setNotes((String) taskDetail.get("notes")); payloadDTO.setText_driver((String) taskDetail.get("text_driver")); payloadDTO.setVoice_driver_cos_file((String) taskDetail.get("voice_driver_cos_file")); tencentCustomserviceDTO.setPayload(payloadDTO); System.out.println(tencentCustomserviceDTO); Map resp = makeVirtualTask(tencentCustomserviceDTO); System.out.println("--------------------------"); System.out.println(resp); Integer respHeaderCode = (Integer) MapUtil.get(resp, "Header.Code"); if (respHeaderCode != 0) { // {Header={RequestID=gz6c6d3da317138514464456410, SessionID=gz6c6d3da317138514464456411, DialogID=, Code=100008, Message=LimitExceeded:超过配额限制: AssetInsufficientError:无可用配额}} String message = (String) MapUtil.get(resp, "Header.Message"); throw new CustException(message); } else { // 2.更新 任务ID、腾讯订单号、备注 String task_id = (String) MapUtil.get(resp, "Payload.TaskId"); aiPersonDTO.setTask_id(task_id); aiPersonDTO.setQuota_code(virtualmanLaunchDTO.getQuota_code()); aiPersonDTO.setTencent_order_code(virtualmanLaunchDTO.getTencent_order_code()); aiPersonDTO.setLaunch_note(virtualmanLaunchDTO.getLaunch_note()); return aiivhMakeVirtualmanTaskService.updateAiivhMakeVirtualmanTask(aiPersonDTO); } } /** * [腾讯-数智人] 查询形象/音色定制进度 */ @Transactional public Map getProgressOfVirtualmanTask(String task_id) { // -- Http Request -------------------------------------------- Map signature = sdkTencentService.getSignature(appKey, accessToken); // 获得 Signature 签名 // System.out.println("signature: " + signature); String url = "https://gw.tvs.qq.com/v2/ivh/assetmanager/customservice/getprogress"; URI uriWithParams = UriComponentsBuilder.fromUriString(url) .queryParam("appkey", signature.get("appkey")) .queryParam("signature", "{signature}") .queryParam("timestamp", signature.get("timestamp")) .build(signature.get("signature")); String jsonStr = "{\"Payload\": {\"TaskId\": \"" + task_id + "\"}}"; JSONObject bodyData = new JSONObject(jsonStr); // System.out.println("task_id: " + task_id); // System.out.println("bodyData: " + bodyData); // Http 远程调用 Map resp = WebClient.create() .method(HttpMethod.POST) .uri(uriWithParams) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(bodyData.toString()) .retrieve().bodyToMono(new ParameterizedTypeReference>() {}) .block(); // // 临时数据 (模拟成功) // Map tempPayload = new LinkedHashMap<>(); // tempPayload.put("StageInfo", "{\"TrainResult\":[\"url1\",\"url2\"],\"RejectReason\":\"\",\"TrainRecord\":[{\"StartTime\":\"2023-11-01 23:00:17\",\"Record\":[\"url1\",\"url2\"]}]}"); // tempPayload.put("Status", "MAKING"); // tempPayload.put("StatusV2", "WAIT_PROCESS"); // tempPayload.put("FailMessage", ""); // tempPayload.put("StageV2", "CONFIRM"); // resp.put("Payload", tempPayload); System.out.println("getProgressOfVirtualmanTask:"); System.out.println(resp); // 判断 任务是否查询成功 (是,则更新数据库记录) Integer respHeaderCode = (Integer) MapUtil.get(resp, "Header.Code"); if (respHeaderCode == 0) { // 任务失败 String respPayloadStage = (String) MapUtil.get(resp, "Payload.Stage"); String respPayloadStageInfo = (String) MapUtil.get(resp, "Payload.StageInfo"); System.out.println("-- respPayloadStageInfo --------"); System.out.println(respPayloadStageInfo); System.out.println("--------------------------------"); // if (respPayloadStage.equals("END")) { // throw new RuntimeException(respPayloadStageInfo); // } String respPayloadStatus = (String) MapUtil.get(resp, "Payload.Status"); // 定制任务完成后, // - 失败,记得把状态改为 1未使用 // - 成功,记得把 quota 状态改为 3已使用 AiivhQuotaDTO aiivhQuotaDTO = new AiivhQuotaDTO(); if ("FAIL".equals(respPayloadStatus)) { aiivhQuotaDTO.setQuota_status(1); } if ("SUCCESS".equals(respPayloadStatus)) { aiivhQuotaDTO.setQuota_status(3); } aiivhQuotaMapper.updateAiivhQuota(aiivhQuotaDTO); // String respPayloadFailMessage = (String) MapUtil.get(resp, "Payload.FailMessage"); /** * 更新任务 */ AiPersonDTO aiPersonDTO = new AiPersonDTO(); // [查询] 自身 UserId Long user_id = httpRequestAspect.getUserId(); aiPersonDTO.setUser_id(user_id); aiPersonDTO.setTask_id(task_id); aiPersonDTO.setTask_status(respPayloadStatus); aiPersonDTO.setTask_status_info(respPayloadStageInfo); aiPersonDTO.setStage_status(respPayloadStage); // 返回值 { Payload } 跟文档不一样,文档是 { StageV2 },实际上是返回 { Stage } // 返回值 { StageInfo } 跟文档不一样,文档是: // {\"TrainResult\":[\"url1\",\"url2\"],\"RejectReason\":\"\",\"TrainRecord\":[{\"StartTime\":\"2023-11-01 23:00:17\",\"Record\":[\"url1\",\"url2\"]}]} // 实际上是: // {"TrainResult":["https://videomaker-resources.ivh.qq.com/broadcast/Basic/video/78f7fb6c6fec4311921ede313f3c7cd5.mp4","https://videomaker-resources.ivh.qq.com/broadcast/Basic/video/259044134def40f69fdfdc1cd6c6c952.mp4"],"RejectReason":"","TrainRecord":[{"StartTime":"2024-03-21 18:06:59","Record":["https://videomaker-resources.ivh.qq.com/broadcast/Basic/video/78f7fb6c6fec4311921ede313f3c7cd5.mp4","https://videomaker-resources.ivh.qq.com/broadcast/Basic/video/259044134def40f69fdfdc1cd6c6c952.mp4"]}]} if (!respPayloadStageInfo.isEmpty()) { JSONObject StageInfoObject = JSONUtil.parseObj(respPayloadStageInfo); String result = JSONUtil.toJsonStr(StageInfoObject); aiPersonDTO.setResult(result); } System.out.println("aiPersonDTO:"); System.out.println(aiPersonDTO); // [Post] 根据 Payload 返回的状态来更新 aiivhMakeVirtualmanTaskService.updateAiivhMakeVirtualmanTask(aiPersonDTO); } return resp; } @Transactional public List> getQueueOfVirtualmanTask(String task_id) { RList rList = redissonClient.getList("makeVirtualTaskQueue"); List queueList = rList.readAll(); List> result = new ArrayList<>(); if (queueList != null && queueList.size() > 0) { for (String queue : queueList) { result.add(JSONUtil.parseObj(queue)); } } return result; } /** * [腾讯-数智人] 确认形象/音色定制效果 */ @Transactional public Map confirmVirtualmanTask(TencentCustomserviceConfirmDTO tencentCustomserviceConfirmDTO) { try { TencentCustomserviceConfirmPlayloadDTO payload = (TencentCustomserviceConfirmPlayloadDTO) tencentCustomserviceConfirmDTO.getPayload(); // 基于实体类,将 anchor_name 转换为 AnchorName (将下划线转为大驼峰) Map resultMap = new HashMap<>(); convertObjectToMap(tencentCustomserviceConfirmDTO, resultMap); String bodyData = JSONUtil.toJsonStr(resultMap); // -- Http Request -------------------------------------------- Map signature = sdkTencentService.getSignature(appKey, accessToken); // 获得 Signature 签名 String url = "https://gw.tvs.qq.com/v2/ivh/assetmanager/customservice/customerconfirm"; URI uriWithParams = UriComponentsBuilder.fromUriString(url) .queryParam("appkey", signature.get("appkey")) .queryParam("signature", "{signature}") .queryParam("timestamp", signature.get("timestamp")) .build(signature.get("signature")); // Http 远程调用 Map resp = WebClient.create() .method(HttpMethod.POST) .uri(uriWithParams) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(bodyData) .retrieve().bodyToMono(new ParameterizedTypeReference>() { }) .block(); System.out.println(resp); // // 临时数据 (模拟成功) // Map tempPayload = new LinkedHashMap<>(); // tempPayload.put("Operate", "AGREE"); //// tempPayload.put("Operate", "REJECT"); //// tempPayload.put("Reason", "REJECT 就是 拒绝"); // resp.put("Payload", tempPayload); // 判断 任务是否确认成功 (是,则更新数据库记录) Integer respHeaderCode = (Integer) MapUtil.get(resp, "Header.Code"); if (respHeaderCode == 0) { AiPersonDTO aiPersonDTO = new AiPersonDTO(); // [查询] 自身 UserId Long user_id = httpRequestAspect.getUserId(); aiPersonDTO.setUser_id(user_id); aiPersonDTO.setTask_id(payload.getTask_id()); String Operate = (String) MapUtil.get(resp, "Payload.Operate"); aiPersonDTO.setConfirm_status(Operate); aiPersonDTO.setConfirm_status_info((String) MapUtil.get(resp, "Payload.Reason")); /** * 更新定制数智人任务 */ aiivhMakeVirtualmanTaskService.updateAiivhMakeVirtualmanTask(aiPersonDTO); /** * 更新形象 (仅更新 stage_status) */ if (Operate == "AGREE") { AiivhAnchorDTO aiivhAnchorDTO = new AiivhAnchorDTO(); //Map detail = aiPersonMapper.queryAiPersonDetail(aiPersonDTO); Map detail = aiivhMakeVirtualmanTaskService.queryAiivhMakeVirtualmanTaskDetail(aiPersonDTO); aiivhAnchorDTO.setUser_id(user_id); aiivhAnchorDTO.setAnchor_name((String) detail.get("anchor_name")); aiivhAnchorDTO.setStage_status((String) detail.get("stage_status")); System.out.println(aiivhAnchorDTO); aiivhMakeVirtualmanTaskService.updateAiPersoneVirtualmanCustom(aiivhAnchorDTO); } } return resp; } catch (IllegalAccessException e) { throw new RuntimeException(e); } } // /** // * 腾讯-数智人-个人资产管理-分页查询小样本形象列表接口 // * https://cloud.tencent.com/document/product/1240/93404 // */ // @Transactional // public Map getCustomVirtualman(Integer pageNum, Integer pageSize) { // Map payload = new HashMap<>(); // payload.put("VirtualmanTypeCode", "small_sample_2d"); //// String[] anchor_codes = new String[]{"imagetrain_100035906086_3416"}; //// payload.put("AnchorCodes", anchor_codes); // payload.put("PageIndex", pageNum); // payload.put("PageSize", pageSize); // // // Map resultMap = Collections.singletonMap("Payload", payload); // String bodyData = JSONUtil.toJsonStr(resultMap); // // // -- Http Request -------------------------------------------- // /** // * 这里使用我自己的空白密钥,因为只有未创建自定义形象的账号,才能返回全部形象 // */ // Map signature = sdkTencentService.getSignature(appKey, accessToken); // 获得 Signature 签名 // // String url = "https://gw.tvs.qq.com/v2/ivh/crmserver/customerassetservice/describesmallsampleimage"; // URI uriWithParams = UriComponentsBuilder.fromUriString(url) // .queryParam("appkey", signature.get("appkey")) // .queryParam("signature", "{signature}") // .queryParam("timestamp", signature.get("timestamp")) // .build(signature.get("signature")); // // // Http 远程调用 // Map resp = WebClient.create() // .method(HttpMethod.POST) // .uri(uriWithParams) // .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) // .bodyValue(bodyData.toString()) // .retrieve().bodyToMono(new ParameterizedTypeReference>() { // }) // .block(); // // Integer respHeaderCode = (Integer) MapUtil.get(resp, "Header.Code"); // if (respHeaderCode == 0) { // List> virtualmans = (List>) MapUtil.get(resp, "Payload.Virtualmans"); // Map response = new LinkedHashMap<>(); // // 遍历 virtualmans 列表,并将 key 由大驼峰改为下划线命名 // virtualmans = ListUtil.convertToUnderscoreCase(virtualmans); // // // // 分页查询 // if (pageNum != null && pageSize != null) { // PageHelper.startPage(pageNum, pageSize); // PageHelper.getLocalPage().setPageSizeZero(true); // } // PageInfoResult pageInfoResult = new PageInfoResult(virtualmans); // return pageInfoResult.toMap(); // } // // return resp; // } /** * 获得全部形象列表 (循环调用接口,至到获得全部数据) * List> virtualmans = getAllVirtualman(pageIndex, pageSize); */ private List> getAllVirtualmanNoEmpty(Integer pageIndex, Integer pageSize) { // 初始化变量 List> timbre_assets = new ArrayList<>(); // 第一次调用 initTimbre 方法,并将当前页的数据追加到 timbre_assets 列表中 Map resp = initCustomVirtualman(pageIndex, pageSize); Integer total = (Integer) MapUtil.get(resp, "Payload.Total"); timbre_assets.addAll((List>) MapUtil.get(resp, "Payload.Virtualmans")); // 循环获取所有页的数据 while (total != null && total > 0 && pageIndex * pageSize <= total) { // 准备下一次查询,页码加1 pageIndex++; System.out.println("pageIndex: " + pageIndex); // 再次调用 initTimbre 方法获取下一页的数据,并将当前页的数据追加到 timbre_assets 列表中 resp = initCustomVirtualman(pageIndex, pageSize); total = (Integer) MapUtil.get(resp, "Payload.Total"); timbre_assets.addAll((List>) MapUtil.get(resp, "Payload.Virtualmans")); } return timbre_assets; } /** * [内部服务] 获得形象详细信息 (通过音色名称) */ @Transactional public Map getVirtualmanObject(String anchor_name) { // 循环获得数据列表,直到 total 小于 pageSize List> virtualmans = getAllVirtualmanNoEmpty(1, 100); // 遍历 virtualmans 列表,并将 key 由大驼峰改为下划线命名 virtualmans = ListUtil.convertToUnderscoreCase(virtualmans); // 遍历 匹配 anchor_name Map result = new LinkedHashMap<>(); for (Map virtualman : virtualmans) { String virtualman_anchor_name = (String) virtualman.get("anchor_name"); // System.out.println("virtualman_anchor_name: " + virtualman_anchor_name + ", anchor_name: " + anchor_name); if (virtualman_anchor_name.equals(anchor_name)) { result = virtualman; System.out.println(virtualman); } } return result; } }