main
HuangHai 2 months ago
parent 33559006d5
commit d17721aa7e

@ -0,0 +1,85 @@
package com.dsideal.aiSupport.Util.KeLing;
public class KlImage2Video {
/*
https /v1/videos/image2video POST application/json application/json
Content-Type application/json
Authorization
model_name string kling-v1 kling-v1, kling-v1-5, kling-v1-6
image string URL访
.jpg / .jpeg / .png
10MB300*300px1:2.5 ~ 2.5:1
image image_tail
image + image_taildynamic_masks/static_maskcamera_control使
{
"code": 0, //错误码;具体定义见错误码
"message": "string", //错误信息
"request_id": "string", //请求ID系统生成用于跟踪请求、排查问题
"data": {
"task_id": "string", //任务ID系统生成
"task_info": {
//任务创建时的参数信息
"external_task_id": "string" //客户自定义任务ID
},
"task_status": "string", //任务状态枚举值submitted已提交、processing处理中、succeed成功、failed失败
"created_at": 1722769557708, //任务创建时间Unix时间戳、单位ms
"updated_at": 1722769557708 //任务更新时间Unix时间戳、单位ms
}
}
https /v1/videos/image2video/{id} GET application/json application/json
Content-Type application/json
Authorization
task_id string ID
external_task_id
external_task_id string ID
external_task_idtask_id
{
"code": 0, //错误码;具体定义见错误码
"message": "string", //错误信息
"request_id": "string", //请求ID系统生成用于跟踪请求、排查问题
"data":{
"task_id": "string", //任务ID系统生成
"task_status": "string", //任务状态枚举值submitted已提交、processing处理中、succeed成功、failed失败
"task_status_msg": "string", //任务状态信息,当任务失败时展示失败原因(如触发平台的内容风控等)
"task_info": { //任务创建时的参数信息
"external_task_id": "string"//客户自定义任务ID
},
"task_result":{
"videos":[
{
"id": "string", //生成的视频ID全局唯一
"url": "string", //生成视频的URL例如https://p1.a.kwimgs.com/bs2/upload-ylab-stunt/special-effect/output/HB1_PROD_ai_web_46554461/-2878350957757294165/output.mp4请注意为保障信息安全生成的图片/视频会在30天后被清理请及时转存
"duration": "string" //视频总时长单位s
}
]
}
"created_at": 1722769557708, //任务创建时间Unix时间戳、单位ms
"updated_at": 1722769557708, //任务更新时间Unix时间戳、单位ms
}
}
* */
}

@ -0,0 +1,309 @@
package com.dsideal.aiSupport.Util.KeLing;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dsideal.aiSupport.Util.KeLing.Kit.KeLingJwtUtil;
import com.dsideal.aiSupport.Util.KeLing.Kit.KlCommon;
import com.dsideal.aiSupport.Util.KeLing.Kit.KlErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* AI
*/
public class KlText2Video extends KlCommon {
private static final Logger log = LoggerFactory.getLogger(KlText2Video.class);
private static final String BASE_URL = "https://api.klingai.com";
private static final String GENERATION_PATH = "/v1/videos/text2video";
private static final String QUERY_PATH = "/v1/videos/text2video/";
/**
*
*
* @param prompt
* @param modelName kling-v1, kling-v1-6
* @return ID
* @throws Exception
*/
public static String generateVideo(String prompt, String modelName) throws Exception {
return generateVideo(prompt, modelName, null);
}
/**
*
*
* @param prompt
* @param modelName kling-v1, kling-v1-6
* @param externalTaskId ID
* @return ID
* @throws Exception
*/
public static String generateVideo(String prompt, String modelName, String externalTaskId) throws Exception {
// 获取JWT令牌
String jwt = KeLingJwtUtil.getJwt();
// 创建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model_name", modelName);
requestBody.put("prompt", prompt);
// 如果提供了外部任务ID则添加到请求体中
if (externalTaskId != null && !externalTaskId.isEmpty()) {
requestBody.put("external_task_id", externalTaskId);
}
// 使用Hutool发送POST请求
HttpResponse response = HttpRequest.post(BASE_URL + GENERATION_PATH)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + jwt)
.body(JSONUtil.toJsonStr(requestBody))
.execute();
log.info("生成视频请求体:{}", JSONUtil.toJsonStr(requestBody));
log.info("生成视频响应体:{}", response.body());
// 检查响应状态码
if (response.getStatus() != 200) {
throw new Exception("请求失败,状态码:" + response.getStatus());
}
// 解析响应
String responseBody = response.body();
JSONObject responseJson = JSONUtil.parseObj(responseBody);
log.info("生成视频响应:{}", responseBody);
// 检查响应状态
int code = responseJson.getInt("code");
if (code != 0) {
String message = responseJson.getStr("message");
String solution = KlErrorCode.getSolutionByCode(code);
String errorMsg = String.format("生成视频失败:[%d] %s - %s", code, message, solution);
// 特殊处理资源包耗尽的情况
if (code == KlErrorCode.RESOURCE_EXHAUSTED.getCode()) {
log.error("可灵AI资源包已耗尽请充值后再试");
throw new Exception("可灵AI资源包已耗尽请充值后再试");
}
throw new Exception(errorMsg);
}
// 获取任务ID
String taskId = responseJson.getJSONObject("data").getStr("task_id");
log.info("生成视频任务ID{}", taskId);
return taskId;
}
/**
*
*
* @param taskId ID
* @return
* @throws Exception
*/
public static JSONObject queryTaskStatus(String taskId) throws Exception {
// 获取JWT令牌
String jwt = KeLingJwtUtil.getJwt();
// 使用Hutool发送GET请求
HttpResponse response = HttpRequest.get(BASE_URL + QUERY_PATH + taskId)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + jwt)
.execute();
// 检查响应状态码
if (response.getStatus() != 200) {
throw new Exception("请求失败,状态码:" + response.getStatus());
}
// 解析响应
String responseBody = response.body();
JSONObject responseJson = JSONUtil.parseObj(responseBody);
log.info("查询任务状态响应:{}", responseBody);
// 检查响应状态
int code = responseJson.getInt("code");
if (code != 0) {
String message = responseJson.getStr("message");
String solution = KlErrorCode.getSolutionByCode(code);
String errorMsg = String.format("查询任务状态失败:[%d] %s - %s", code, message, solution);
throw new Exception(errorMsg);
}
return responseJson;
}
/**
* ID
*
* @param externalTaskId ID
* @return
* @throws Exception
*/
public static JSONObject queryTaskStatusByExternalId(String externalTaskId) throws Exception {
// 获取JWT令牌
String jwt = KeLingJwtUtil.getJwt();
// 使用Hutool发送GET请求
HttpResponse response = HttpRequest.get(BASE_URL + GENERATION_PATH + "?external_task_id=" + externalTaskId)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + jwt)
.execute();
// 检查响应状态码
if (response.getStatus() != 200) {
throw new Exception("请求失败,状态码:" + response.getStatus());
}
// 解析响应
String responseBody = response.body();
JSONObject responseJson = JSONUtil.parseObj(responseBody);
log.info("查询任务状态响应:{}", responseBody);
// 检查响应状态
int code = responseJson.getInt("code");
if (code != 0) {
String message = responseJson.getStr("message");
String solution = KlErrorCode.getSolutionByCode(code);
String errorMsg = String.format("查询任务状态失败:[%d] %s - %s", code, message, solution);
throw new Exception(errorMsg);
}
return responseJson;
}
/**
* URL
*
* @param fileUrl URL
* @param saveFilePath
* @throws Exception
*/
public static void downloadFile(String fileUrl, String saveFilePath) throws Exception {
try {
// 使用Hutool下载文件
long fileSize = HttpUtil.downloadFile(fileUrl, FileUtil.file(saveFilePath));
log.info("文件下载成功,保存路径: {}, 文件大小: {}字节", saveFilePath, fileSize);
} catch (Exception e) {
log.error("文件下载失败: {}", e.getMessage(), e);
throw e;
}
}
public static void main(String[] args) throws Exception {
// 提示词和模型名称
String prompt = "一只可爱的小猫咪在草地上奔跑,阳光明媚";
String modelName = "kling-v1"; // 可选kling-v1, kling-v1-6
// 生成外部任务ID可选
String externalTaskId = "video_" + UUID.randomUUID().toString().replace("-", "");
// 添加重试逻辑
int generateRetryCount = 0;
int maxGenerateRetries = 5; // 最大重试次数
int generateRetryInterval = 5000; // 重试间隔(毫秒)
String taskId = null;
boolean accountIssue = false;
while (generateRetryCount < maxGenerateRetries && !accountIssue) {
try {
taskId = generateVideo(prompt, modelName, externalTaskId);
break;
} catch (Exception e) {
log.error("生成视频异常: {}", e.getMessage(), e);
// 检查是否是账户问题
if (e.getMessage().contains("资源包已耗尽") ||
e.getMessage().contains("账户欠费") ||
e.getMessage().contains("无权限")) {
log.error("账户问题,停止重试");
accountIssue = true;
} else {
generateRetryCount++;
if (generateRetryCount < maxGenerateRetries) {
log.warn("等待{}毫秒后重试...", generateRetryInterval);
Thread.sleep(generateRetryInterval);
} else {
throw e; // 达到最大重试次数,抛出异常
}
}
}
}
if (taskId == null) {
if (accountIssue) {
log.error("账户问题,请检查账户状态或充值后再试");
} else {
log.error("生成视频失败,已达到最大重试次数: {}", maxGenerateRetries);
}
return;
}
// 查询任务状态
int queryRetryCount = 0;
int maxQueryRetries = 60; // 最大查询次数
int queryRetryInterval = 5000; // 查询间隔(毫秒)
while (queryRetryCount < maxQueryRetries) {
try {
JSONObject result = queryTaskStatus(taskId);
JSONObject data = result.getJSONObject("data");
String taskStatus = data.getStr("task_status");
if ("failed".equals(taskStatus)) {
String taskStatusMsg = data.getStr("task_status_msg");
log.error("任务失败: {}", taskStatusMsg);
break;
} else if ("succeed".equals(taskStatus)) {
// 获取视频URL
JSONObject taskResult = data.getJSONObject("task_result");
JSONArray videos = taskResult.getJSONArray("videos");
for (int i = 0; i < videos.size(); i++) {
JSONObject video = videos.getJSONObject(i);
String videoId = video.getStr("id");
String videoUrl = video.getStr("url");
String duration = video.getStr("duration");
log.info("视频ID: {}, 时长: {}秒", videoId, duration);
// 下载视频
String saveVideoPath = basePath + "video_" + videoId + ".mp4";
log.info("开始下载视频...");
downloadFile(videoUrl, saveVideoPath);
log.info("视频已下载到: {}", saveVideoPath);
}
break;
} else {
log.info("任务状态: {}, 等待{}毫秒后重试...", taskStatus, queryRetryInterval);
Thread.sleep(queryRetryInterval);
queryRetryCount++;
}
} catch (Exception e) {
log.error("查询任务状态异常: {}", e.getMessage(), e);
queryRetryCount++;
if (queryRetryCount < maxQueryRetries) {
log.warn("等待{}毫秒后重试...", queryRetryInterval);
Thread.sleep(queryRetryInterval);
} else {
throw e; // 达到最大重试次数,抛出异常
}
}
}
if (queryRetryCount >= maxQueryRetries) {
log.error("任务查询超时,已达到最大查询次数: {}", maxQueryRetries);
}
}
}
Loading…
Cancel
Save