diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/Kit/VideoStyleEnum.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/Kit/VideoStyleEnum.java new file mode 100644 index 00000000..b954294d --- /dev/null +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/Kit/VideoStyleEnum.java @@ -0,0 +1,115 @@ +package com.dsideal.aiSupport.Util.DashScope.Kit; + +/** + * 阿里云达摩院视频风格转换类型枚举 + */ +public enum VideoStyleEnum { + /** + * 日式漫画(默认值) + */ + JAPANESE_COMIC(0, "日式漫画"), + + /** + * 美式漫画 + */ + AMERICAN_COMIC(1, "美式漫画"), + + /** + * 清新漫画 + */ + FRESH_COMIC(2, "清新漫画"), + + /** + * 3D卡通 + */ + CARTOON_3D(3, "3D卡通"), + + /** + * 国风卡通 + */ + CHINESE_CARTOON(4, "国风卡通"), + + /** + * 纸艺风格 + */ + PAPER_ART(5, "纸艺风格"), + + /** + * 简易插画 + */ + SIMPLE_ILLUSTRATION(6, "简易插画"), + + /** + * 国风水墨 + */ + CHINESE_INK(7, "国风水墨"); + + /** + * 风格类型值 + */ + private final int value; + + /** + * 风格类型描述 + */ + private final String description; + + /** + * 构造函数 + * + * @param value 风格类型值 + * @param description 风格类型描述 + */ + VideoStyleEnum(int value, String description) { + this.value = value; + this.description = description; + } + + /** + * 获取风格类型值 + * + * @return 风格类型值 + */ + public int getValue() { + return value; + } + + /** + * 获取风格类型描述 + * + * @return 风格类型描述 + */ + public String getDescription() { + return description; + } + + /** + * 根据风格类型值获取枚举 + * + * @param value 风格类型值 + * @return 对应的枚举,如果不存在则返回默认值(日式漫画) + */ + public static VideoStyleEnum fromValue(int value) { + for (VideoStyleEnum style : VideoStyleEnum.values()) { + if (style.getValue() == value) { + return style; + } + } + return JAPANESE_COMIC; // 默认返回日式漫画 + } + + /** + * 根据风格类型描述获取枚举 + * + * @param description 风格类型描述 + * @return 对应的枚举,如果不存在则返回默认值(日式漫画) + */ + public static VideoStyleEnum fromDescription(String description) { + for (VideoStyleEnum style : VideoStyleEnum.values()) { + if (style.getDescription().equals(description)) { + return style; + } + } + return JAPANESE_COMIC; // 默认返回日式漫画 + } +} \ No newline at end of file diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/video_style_transform.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/video_style_transform.java new file mode 100644 index 00000000..85d70f7d --- /dev/null +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/video_style_transform.java @@ -0,0 +1,262 @@ +package com.dsideal.aiSupport.Util.DashScope; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.dsideal.aiSupport.Plugin.YamlProp; +import com.dsideal.aiSupport.Util.DashScope.Kit.VideoStyleEnum; +import com.jfinal.kit.Prop; +import lombok.SneakyThrows; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +import static com.dsideal.aiSupport.AiSupportApplication.getEnvPrefix; + +/** + * 阿里云达摩院视频风格转换API工具类 + */ +public class video_style_transform { + private static final Logger log = LoggerFactory.getLogger(video_style_transform.class); + private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis"; + private static final String API_KEY; + + public static Prop PropKit; // 配置文件工具 + + static { + //加载配置文件 + String configFile = "application_{?}.yaml".replace("{?}", getEnvPrefix()); + PropKit = new YamlProp(configFile); + API_KEY = PropKit.get("aliyun.API_KEY"); + } + + /** + * 调用视频风格转换API + * + * @param videoUrl 视频URL + * @param style 风格类型,0-9之间的整数 + * @param videoFps 视频帧率,默认为15 + * @return 任务ID + * @throws Exception 异常信息 + */ + @SneakyThrows + public static String transformVideoStyle(String videoUrl, int style, int videoFps) { + // 创建OkHttpClient,设置超时时间 + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build(); + + // 构建请求体 + JSONObject requestBody = new JSONObject(); + requestBody.put("model", "video-style-transform"); + + // 设置输入参数 + JSONObject input = new JSONObject(); + input.put("video_url", videoUrl); + requestBody.put("input", input); + + // 设置其他参数 + JSONObject parameters = new JSONObject(); + parameters.put("style", style); + parameters.put("video_fps", videoFps); + requestBody.put("parameters", parameters); + + // 创建请求 + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString()); + Request request = new Request.Builder() + .url(API_URL) + .method("POST", body) + .addHeader("Content-Type", "application/json") + .addHeader("Authorization", "Bearer " + API_KEY) + .addHeader("X-DashScope-Async", "enable") + .addHeader("X-DashScope-DataInspection", "enable") + .build(); + + // 发送请求并获取响应 + log.info("发送视频风格转换请求: {}", requestBody.toJSONString()); + Response response = client.newCall(request).execute(); + + // 检查响应状态 + if (!response.isSuccessful()) { + log.info(response.message()); + String errorMsg = "视频风格转换API请求失败,状态码: " + response.code(); + log.error(errorMsg); + throw new Exception(errorMsg); + } + + // 解析响应 + String responseBody = response.body().string(); + log.info("视频风格转换响应: {}", responseBody); + + JSONObject responseJson = JSON.parseObject(responseBody); + + // 获取任务ID + String taskId = responseJson.getJSONObject("output").getString("task_id"); + log.info("视频风格转换任务ID: {}", taskId); + + return taskId; + } + + /** + * 查询任务状态 + * + * @param taskId 任务ID + * @return 任务结果 + * @throws Exception 异常信息 + */ + @SneakyThrows + public static JSONObject queryTaskStatus(String taskId) { + // 创建OkHttpClient + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + + // 创建请求 + Request request = new Request.Builder() + .url("https://dashscope.aliyuncs.com/api/v1/tasks/" + taskId) + .method("GET", null) + .addHeader("Authorization", "Bearer " + API_KEY) + .build(); + + // 发送请求并获取响应 + log.info("查询视频风格转换任务状态: {}", taskId); + Response response = client.newCall(request).execute(); + + // 检查响应状态 + if (!response.isSuccessful()) { + String errorMsg = "视频风格转换API请求失败,状态码: " + response.code(); + log.error(errorMsg); + throw new Exception(errorMsg); + } + + // 解析响应 + String responseBody = response.body().string(); + log.info("查询视频风格转换任务状态响应: {}", responseBody); + + return JSON.parseObject(responseBody); + } + + /** + * 下载视频并保存到本地 + * + * @param videoUrl 视频URL + * @param savePath 保存路径 + * @throws Exception 异常信息 + */ + @SneakyThrows + public static void downloadVideo(String videoUrl, String savePath) { + // 创建OkHttpClient + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .build(); + + // 创建请求 + Request request = new Request.Builder() + .url(videoUrl) + .method("GET", null) + .build(); + + // 发送请求并获取响应 + log.info("开始下载视频: {}", videoUrl); + Response response = client.newCall(request).execute(); + + // 检查响应状态 + if (!response.isSuccessful()) { + String errorMsg = "下载视频失败,状态码: " + response.code(); + log.error(errorMsg); + throw new Exception(errorMsg); + } + + // 确保目录存在 + java.io.File file = new java.io.File(savePath); + java.io.File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + log.info("创建目录: {}", parentDir.getAbsolutePath()); + } + + // 保存视频 + try (java.io.InputStream inputStream = response.body().byteStream(); + java.io.FileOutputStream outputStream = new java.io.FileOutputStream(savePath)) { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + } + + log.info("视频下载成功,保存路径: {}", savePath); + } + + /** + * 使用示例 + */ + @SneakyThrows + public static void main(String[] args) { + // 视频URL + String videoUrl = "https://dsideal.obs.myhuaweicloud.com/HuangHai/%E5%A4%87%E4%BB%BD/girl.mp4"; + // 风格类型,0-9之间的整数 + VideoStyleEnum styleEnum = VideoStyleEnum.CHINESE_INK; // 国风水墨风格 + int style = styleEnum.getValue(); // 获取对应的值:7 + + // 在API调用中使用 + // 视频帧率 + int videoFps = 15; + + // 调用视频风格转换API + String taskId = transformVideoStyle(videoUrl, style, videoFps); + + // 轮询查询任务状态 + int maxRetries = 100; + int retryCount = 0; + int retryInterval = 5000; // 5秒 + String resultVideoUrl = null; + + while (retryCount < maxRetries) { + JSONObject result = queryTaskStatus(taskId); + String status = result.getJSONObject("output").getString("status"); + log.info("任务状态: {}", status); + + if ("SUCCEEDED".equals(status)) { + // 任务成功,获取视频URL + resultVideoUrl = result.getJSONObject("output").getString("url"); + log.info("生成的视频URL: {}", resultVideoUrl); + break; + } else if ("FAILED".equals(status)) { + // 任务失败 + String message = result.getJSONObject("output").getString("message"); + log.error("任务失败: {}", message); + break; + } else { + // 任务仍在进行中,等待后重试 + log.info("任务进行中,等待{}毫秒后重试...", retryInterval); + Thread.sleep(retryInterval); + retryCount++; + } + } + + if (retryCount >= maxRetries) { + log.error("查询任务状态超时,已达到最大重试次数: {}", maxRetries); + } + + // 如果获取到了视频URL,则下载保存 + if (resultVideoUrl != null && !resultVideoUrl.isEmpty()) { + // 创建保存目录 + String saveDir = System.getProperty("user.dir") + "/style_videos"; + // 生成文件名(使用时间戳和任务ID) + String fileName = "style_" + System.currentTimeMillis() + "_" + taskId + ".mp4"; + // 完整保存路径 + String savePath = saveDir + "/" + fileName; + + // 下载视频 + downloadVideo(resultVideoUrl, savePath); + } + } +}