diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/Text2Img.jpg b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/Text2Img.jpg new file mode 100644 index 00000000..d66bc84d Binary files /dev/null and b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/Text2Img.jpg differ diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmImg2Video.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmImg2Video.java index df3ed3bf..3b519b77 100644 --- a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmImg2Video.java +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmImg2Video.java @@ -8,11 +8,6 @@ import com.dsideal.aiSupport.Util.JiMeng.Kit.JmErrorCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.*; public class JmImg2Video extends JmCommon { @@ -44,49 +39,6 @@ public class JmImg2Video extends JmCommon { return JSON.parseObject(responseBody); } - /** - * 从URL下载文件到指定路径 - * - * @param fileUrl 文件URL - * @param saveFilePath 保存路径 - * @throws Exception 下载过程中的异常 - */ - public static void downloadFile(String fileUrl, String saveFilePath) throws Exception { - URL url = new URL(fileUrl); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setConnectTimeout(5000); - connection.setReadTimeout(60000); - - // 确保目录存在 - File file = new File(saveFilePath); - File parentDir = file.getParentFile(); - if (parentDir != null && !parentDir.exists()) { - parentDir.mkdirs(); - log.info("创建目录: {}", parentDir.getAbsolutePath()); - } - - // 获取输入流 - try (InputStream in = connection.getInputStream(); - FileOutputStream out = new FileOutputStream(saveFilePath)) { - - byte[] buffer = new byte[4096]; - int bytesRead; - - // 读取数据并写入文件 - while ((bytesRead = in.read(buffer)) != -1) { - out.write(buffer, 0, bytesRead); - } - - log.info("文件下载成功,保存路径: {}", saveFilePath); - } catch (Exception e) { - log.error("文件下载失败: {}", e.getMessage(), e); - throw e; - } finally { - connection.disconnect(); - } - } - public static void main(String[] args) throws Exception { //玩法: //https://www.volcengine.com/docs/85621/1544774 diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Img.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Img.java index 3ca1ac21..c9ec67de 100644 --- a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Img.java +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Img.java @@ -8,8 +8,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; import java.util.*; public class JmText2Img extends JmCommon { @@ -51,40 +49,30 @@ public class JmText2Img extends JmCommon { log.info("创建目录: {}", parentDir.getAbsolutePath()); } - // 对 Base64 字符串进行解码 - Base64.Decoder decoder = Base64.getDecoder(); - byte[] bytes = decoder.decode(imgBase64); - - try (OutputStream os = new FileOutputStream(saveImgPath)) { // 使用-with try-resources 自动关闭资源 - os.write(bytes); - os.flush(); // 刷新缓冲区,确保数据写入文件 - log.info("文件保存成功!文件位置: {}", saveImgPath); - } catch (Exception e) { - log.error("文件保存失败!{}", e.getMessage(), e); - throw new Exception("文件保存失败: " + e.getMessage(), e); - } + // 对 Base64 字符串进行解码并保存为文件 + byte[] bytes = Base64.getDecoder().decode(imgBase64); + cn.hutool.core.io.FileUtil.writeBytes(bytes, saveImgPath); + log.info("文件保存成功!文件位置: {}", saveImgPath); } public static void main(String[] args) throws Exception { //更多例子参考:https://www.volcengine.com/docs/85621/1537648 //String prompt = "制作一张vlog视频封面。马卡龙配色,美女旅游照片+色块的拼贴画风格,主文案是"威海旅游vlog",副文案是"特种兵一日游 被低估的旅游城市",海报主体是一个穿着短裙、梳双马尾的少女,人物白色描边"; //String prompt = "过曝,强对比,夜晚,雪地里,巨大的黄色浴缸,小狗泡澡带墨镜,在喝红酒,胶片摄影,毛刺质感,复古滤镜,夜晚,过度曝光,古早,70年代摄影,复古老照片,闪光灯拍摄,闪光灯效果,过曝,过度曝光,闪光灯过曝,极简,高饱和复古色,70s vintage photography, vintage, retro style"; - String prompt="南瓜羹->画面展现一碗百合南瓜羹的一半,米黄色的糯米粉勾芡,块块橙色南瓜在橙色粥中,南瓜丝丝沙沙质感,紫白色百合点缀"; + //String prompt="南瓜羹->画面展现一碗百合南瓜羹的一半,米黄色的糯米粉勾芡,块块橙色南瓜在橙色粥中,南瓜丝丝沙沙质感,紫白色百合点缀"; + //String prompt="一张海报,画面上方有手写涂鸦风格的文字写着:新年快乐"; + String prompt="工笔画风格,三维古风,东方禅意,航拍高角度视角,捕捉了海底极小人物的奔跑追逐;构图大面积留白和丰富的光影,背景以水墨晕染展现水中阳光的多彩折射,现实与虚拟相结合的思考,水墨风格,蓝绿色调,逆光和辉光效果增强冷暖对比,高角度拍摄景深感,整体画面高清,画质通透,发光呈现幽静空灵感"; // 获取项目根目录路径 - String projectRoot = System.getProperty("user.dir"); - // 拼接相对路径 - String basePath = projectRoot + "/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/"; - String saveImagePath = basePath + "3.jpg"; - + String saveImagePath = basePath + "Text2Img.jpg"; log.info("保存图片路径:{}", saveImagePath); - + // 添加重试逻辑,处理API并发限制错误 int retryCount = 0; - int maxRetries = 5; // 最大重试次数 + int maxRetries = 1000; // 最大重试次数 int retryInterval = 5000; // 重试间隔(毫秒) - while (retryCount < maxRetries) { + while (true) { try { JmText2Img.generateImage(prompt, saveImagePath); // 成功生成图片,跳出循环 diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Video.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Video.java index 9fbee42f..a513f964 100644 --- a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Video.java +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/JmText2Video.java @@ -8,10 +8,6 @@ import com.jfinal.kit.StrKit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.*; public class JmText2Video extends JmCommon { @@ -34,42 +30,6 @@ public class JmText2Video extends JmCommon { return JSON.parseObject(responseBody); } - /** - * 从URL下载文件到指定路径 - * - * @param fileUrl 文件URL - * @param saveFilePath 保存路径 - * @throws Exception 下载过程中的异常 - */ - public static void downloadFile(String fileUrl, String saveFilePath) throws Exception { - URL url = new URL(fileUrl); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setConnectTimeout(5000); - connection.setReadTimeout(60000); - - // 获取输入流 - try (InputStream in = connection.getInputStream(); - FileOutputStream out = new FileOutputStream(saveFilePath)) { - - byte[] buffer = new byte[4096]; - int bytesRead; - - // 读取数据并写入文件 - while ((bytesRead = in.read(buffer)) != -1) { - out.write(buffer, 0, bytesRead); - } - - log.info("文件下载成功,保存路径: {}", saveFilePath); - } catch (Exception e) { - log.error("文件下载失败: {}", e.getMessage(), e); - throw e; - } finally { - connection.disconnect(); - } - } - - public static void main(String[] args) throws Exception { String prompt = "蓝色毛绒玩具在超市里拖地,结果拖把洒出好多五颜六色的粉末,接着把粉末洒向镜头前,镜头随之穿过粉末"; //保存的文件名称 diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmCommon.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmCommon.java index 53f25610..0ac32273 100644 --- a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmCommon.java +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmCommon.java @@ -1,14 +1,22 @@ package com.dsideal.aiSupport.Util.JiMeng.Kit; +import cn.hutool.http.Method; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.dsideal.aiSupport.Plugin.YamlProp; import com.google.common.io.ByteStreams; import com.jfinal.kit.Prop; import org.apache.commons.codec.binary.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import cn.hutool.core.io.FileUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -27,6 +35,8 @@ import static com.dsideal.aiSupport.AiSupportApplication.getEnvPrefix; * 用于处理火山引擎API的请求签名和发送 */ public class JmCommon { + private static final Logger log = LoggerFactory.getLogger(JmCommon.class); + // 请求域名 public static String host = "visual.volcengineapi.com"; public static String path = "/"; // 路径,不包含 Query @@ -35,20 +45,21 @@ public class JmCommon { public static String region = "cn-north-1"; // 区域,固定为cn-north-1 public static String schema = "https"; // 协议,使用https public static String version = "2022-08-31"; // API版本号 - + // URL编码相关常量 private static final BitSet URLENCODER = new BitSet(256); private static final String CONST_ENCODE = "0123456789ABCDEF"; public static final Charset UTF_8 = StandardCharsets.UTF_8; - + // API访问凭证 protected static final String ak; // Access Key protected static final String sk; // Secret Key public static Prop PropKit; // 配置文件工具 // 获取项目根目录路径 - protected static String projectRoot = System.getProperty("user.dir").replace("\\","/")+"/dsAiSupport"; + protected static String projectRoot = System.getProperty("user.dir").replace("\\", "/") + "/dsAiSupport"; // 拼接相对路径 protected static String basePath = projectRoot + "/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/"; + /** * 静态初始化块 * 加载配置文件并初始化URL编码器 @@ -77,14 +88,13 @@ public class JmCommon { URLENCODER.set('~'); } - /** - * 发送HTTP请求到火山引擎API - * - * @param method 请求方法,如GET、POST + * 使用Hutool发送HTTP请求到火山引擎API + * + * @param method 请求方法,如GET、POST * @param queryList 查询参数列表 - * @param body 请求体数据 - * @param action API操作名称 + * @param body 请求体数据 + * @param action API操作名称 * @return 响应体字符串 * @throws Exception 请求过程中的异常 */ @@ -95,13 +105,13 @@ public class JmCommon { } // 计算请求体的SHA256哈希值 String xContentSha256 = hashSHA256(body); - + // 格式化日期时间,用于请求头 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); String xDate = sdf.format(date); String shortXDate = xDate.substring(0, 8); // 提取日期部分,用于凭证范围 - + String contentType = "application/json"; // 内容类型 String signHeader = "host;x-date;x-content-sha256;content-type"; // 签名头部列表 @@ -124,10 +134,10 @@ public class JmCommon { "\n" + signHeader + "\n" + xContentSha256; - + // 计算规范请求字符串的哈希值 String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes()); - + // 构建凭证范围和签名字符串 String credentialScope = shortXDate + "/" + region + "/" + service + "/request"; String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString; @@ -135,50 +145,70 @@ public class JmCommon { // 生成签名密钥并计算签名 byte[] signKey = genSigningSecretKeyV4(shortXDate, region, service); String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString)); - - // 构建URL并创建HTTP连接 - URL url = new URL(schema + "://" + host + path + "?" + querySB); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod(method); - + + // 构建URL + String url = schema + "://" + host + path + "?" + querySB; + + // 使用Hutool发送HTTP请求 + HttpRequest request = HttpRequest.of(url); + // 将字符串方法名转换为Method枚举 + Method httpMethod = Method.valueOf(method.toUpperCase()); + request.method(httpMethod); + // 设置请求头 - conn.setRequestProperty("Host", host); - conn.setRequestProperty("X-Date", xDate); - conn.setRequestProperty("X-Content-Sha256", xContentSha256); - conn.setRequestProperty("Content-Type", contentType); - conn.setRequestProperty("Authorization", "HMAC-SHA256" + + request.header("Host", host); + request.header("X-Date", xDate); + request.header("X-Content-Sha256", xContentSha256); + request.header("Content-Type", contentType); + request.header("Authorization", "HMAC-SHA256" + " Credential=" + ak + "/" + credentialScope + ", SignedHeaders=" + signHeader + ", Signature=" + signature); - - // 如果不是GET请求,写入请求体 - if (!Objects.equals(conn.getRequestMethod(), "GET")) { - conn.setDoOutput(true); - OutputStream os = conn.getOutputStream(); - os.write(body); - os.flush(); - os.close(); - } - - // 建立连接并获取响应 - conn.connect(); - int responseCode = conn.getResponseCode(); - InputStream is; - if (responseCode == 200) { - is = conn.getInputStream(); // 成功响应 - } else { - is = conn.getErrorStream(); // 错误响应 + + // 如果不是GET请求,设置请求体 + if (!method.equals("GET") && body.length > 0) { + request.body(body); } - - // 读取响应内容并关闭流 - String responseBody = new String(ByteStreams.toByteArray(is)); - is.close(); + + // 发送请求并获取响应 + HttpResponse response = request.execute(); + String responseBody = response.body(); + + // 关闭响应 + response.close(); + return responseBody; } + /** + * 从URL下载文件到指定路径 + * + * @param fileUrl 文件URL + * @param saveFilePath 保存路径 + * @throws Exception 下载过程中的异常 + */ + public static void downloadFile(String fileUrl, String saveFilePath) throws Exception { + try { + // 确保目录存在 + File file = new File(saveFilePath); + File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + log.info("创建目录: {}", parentDir.getAbsolutePath()); + } + + // 使用Hutool下载文件 + long fileSize = HttpUtil.downloadFile(fileUrl, FileUtil.file(saveFilePath)); + log.info("文件下载成功,保存路径: {}, 文件大小: {}字节", saveFilePath, fileSize); + } catch (Exception e) { + log.error("文件下载失败: {}", e.getMessage(), e); + throw new Exception("文件下载失败: " + e.getMessage(), e); + } + } + /** * URL编码字符串,用于签名 - * + * * @param source 源字符串 * @return 编码后的字符串 */ @@ -211,7 +241,7 @@ public class JmCommon { /** * 计算内容的SHA256哈希值 - * + * * @param content 要计算哈希的内容 * @return 十六进制表示的哈希值 * @throws Exception 计算过程中的异常 @@ -227,8 +257,8 @@ public class JmCommon { /** * 使用HMAC-SHA256算法计算消息认证码 - * - * @param key 密钥 + * + * @param key 密钥 * @param content 内容 * @return 计算结果 * @throws Exception 计算过程中的异常 @@ -246,9 +276,9 @@ public class JmCommon { /** * 生成V4版本的签名密钥 * 使用AWS签名V4算法的派生密钥过程 - * - * @param date 日期字符串 - * @param region 区域 + * + * @param date 日期字符串 + * @param region 区域 * @param service 服务名称 * @return 派生的签名密钥 * @throws Exception 生成过程中的异常 diff --git a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmErrorCode.java b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmErrorCode.java index 6e036d76..74317b0d 100644 --- a/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmErrorCode.java +++ b/dsAiSupport/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Kit/JmErrorCode.java @@ -1,8 +1,11 @@ package com.dsideal.aiSupport.Util.JiMeng.Kit; +import lombok.Getter; + /** * 火山引擎API错误码枚举 */ +@Getter public enum JmErrorCode { SUCCESS(10000, "请求成功"), @@ -18,15 +21,7 @@ public enum JmErrorCode { this.code = code; this.message = message; } - - public int getCode() { - return code; - } - - public String getMessage() { - return message; - } - + /** * 根据错误码获取枚举实例 * @param code 错误码