From 497adf10c36d2ccb3fc182d8b591013b8cd4d99e Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Tue, 13 May 2025 15:22:48 +0800 Subject: [PATCH] 'commit' --- .../Util/DashScope/DsEmoVideoSynthesis.java | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/DsEmoVideoSynthesis.java diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/DsEmoVideoSynthesis.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/DsEmoVideoSynthesis.java new file mode 100644 index 00000000..73417015 --- /dev/null +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/DashScope/DsEmoVideoSynthesis.java @@ -0,0 +1,266 @@ +package com.dsideal.aiSupport.Util.DashScope; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.dsideal.aiSupport.Plugin.YamlProp; +import com.jfinal.kit.Prop; +import lombok.SneakyThrows; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import static com.dsideal.aiSupport.AiSupportApplication.getEnvPrefix; + +/** + * 阿里云达摩院EMO视频合成API工具类 + */ +public class DsEmoVideoSynthesis { + private static final Logger log = LoggerFactory.getLogger(DsEmoVideoSynthesis.class); + private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/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"); + } + + /** + * 调用EMO视频合成API + * + * @param imageUrl 图片URL + * @param audioUrl 音频URL + * @param faceBbox 人脸边界框 [x, y, width, height] + * @param extBbox 扩展边界框 [x, y, width, height] + * @param styleLevel 风格级别,可选值:normal, strong + * @return 任务ID + * @throws Exception 异常信息 + */ + @SneakyThrows + public static String synthesisVideo(String imageUrl, String audioUrl, int[] faceBbox, int[] extBbox, String styleLevel) { + // 创建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", "emo-v1"); + + // 设置输入参数 + JSONObject input = new JSONObject(); + input.put("image_url", imageUrl); + input.put("audio_url", audioUrl); + input.put("face_bbox", faceBbox); + input.put("ext_bbox", extBbox); + requestBody.put("input", input); + + // 设置其他参数 + JSONObject parameters = new JSONObject(); + parameters.put("style_level", styleLevel); + 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") + .build(); + + // 发送请求并获取响应 + log.info("发送EMO视频合成请求: {}", requestBody.toJSONString()); + Response response = client.newCall(request).execute(); + + // 检查响应状态 + if (!response.isSuccessful()) { + log.info(response.message()); + String errorMsg = "EMO视频合成API请求失败,状态码: " + response.code(); + log.error(errorMsg); + throw new Exception(errorMsg); + } + + // 解析响应 + String responseBody = response.body().string(); + log.info("EMO视频合成响应: {}", responseBody); + + JSONObject responseJson = JSON.parseObject(responseBody); + + // 获取任务ID + String taskId = responseJson.getJSONObject("output").getString("task_id"); + log.info("EMO视频合成任务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(API_URL + taskId) + .method("GET", null) + .addHeader("Authorization", "Bearer " + API_KEY) + .build(); + + // 发送请求并获取响应 + log.info("查询EMO视频合成任务状态: {}", taskId); + Response response = client.newCall(request).execute(); + + // 检查响应状态 + if (!response.isSuccessful()) { + String errorMsg = "EMO视频合成API请求失败,状态码: " + response.code(); + log.error(errorMsg); + throw new Exception(errorMsg); + } + + // 解析响应 + String responseBody = response.body().string(); + log.info("查询EMO视频合成任务状态响应: {}", 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 imageUrl = "https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202505131058596.png"; + // 音频URL + String audioUrl = "https://dsideal.obs.myhuaweicloud.com/HuangHai/%E5%A4%87%E4%BB%BD/%E5%A4%A7%E5%AE%B6%E5%A5%BD%EF%BC%8C%E8%BF%99%E9%87%8C%E6%98%AF%E6%B5%B7%E5%93%A5AI%E8%AF%BE%E7%A8%8B%EF%BC%8C%E6%88%91%E6%98%AF%E5%B8%AE%E4%BD%A0%E5%AE%9E%E7%8E%B0%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%8F%98%E7%8E%B0%E7%9A%84%E6%B5%B7%E5%93%A5%E3%80%82.wav"; + // 人脸边界框 [x, y, width, height] + int[] faceBbox = {10, 20, 30, 40}; + // 扩展边界框 [x, y, width, height] + int[] extBbox = {10, 20, 30, 40}; + // 风格级别 + String styleLevel = "normal"; + + // 调用EMO视频合成API + String taskId = synthesisVideo(imageUrl, audioUrl, faceBbox, extBbox, styleLevel); + + // 轮询查询任务状态 + int maxRetries = 100; + int retryCount = 0; + int retryInterval = 5000; // 5秒 + String videoUrl = null; + + while (retryCount < maxRetries) { + JSONObject result = queryTaskStatus(taskId); + String status = result.getJSONObject("output").getString("status"); + log.info("任务状态: {}", status); + + if ("SUCCEEDED".equals(status)) { + // 任务成功,获取视频URL + videoUrl = result.getJSONObject("output").getString("url"); + log.info("生成的视频URL: {}", videoUrl); + 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 (videoUrl != null && !videoUrl.isEmpty()) { + // 创建保存目录 + String saveDir = System.getProperty("user.dir") + "/emo_videos"; + // 生成文件名(使用时间戳和任务ID) + String fileName = "emo_" + System.currentTimeMillis() + "_" + taskId + ".mp4"; + // 完整保存路径 + String savePath = saveDir + "/" + fileName; + + // 下载视频 + downloadVideo(videoUrl, savePath); + } + } +} \ No newline at end of file