main
HuangHai 2 months ago
parent b6b603eb30
commit 9704892500

@ -10,6 +10,7 @@ import javax.crypto.spec.SecretKeySpec;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
@ -18,53 +19,50 @@ import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* API
* API
*/
public class JmCommon {
// 请求域名
public static String host = "visual.volcengineapi.com";
public static String path = "/"; // 路径,不包含 Query// 请求接口信息
public static String service = "cv";
public static String region = "cn-north-1";
public static String schema = "https";
public static String version = "2022-08-31";
public static String path = "/"; // 路径,不包含 Query
// 请求接口信息
public static String service = "cv"; // 服务名称固定为cv
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;
protected static final String ak;
protected static final String sk;
public static Prop PropKit;
// API访问凭证
protected static final String ak; // Access Key
protected static final String sk; // Secret Key
public static Prop PropKit; // 配置文件工具
/**
*
* URL
*/
static {
//加载配置文件
String configFile = "application_{?}.yaml".replace("{?}", getEnvPrefix());
PropKit = new YamlProp(configFile);
System.out.println("当前环境: " + getEnvPrefix());
// 火山官网密钥信息, 注意sk结尾有==
ak = PropKit.get("JiMeng.ak");
sk = PropKit.get("JiMeng.sk");
}
/**
*
*
* @return
*/
public static String getEnvPrefix() {
String myEnvVar = System.getenv("WORKING_ENV");
if (myEnvVar == null) {
myEnvVar = "dev";
}
return myEnvVar;
}
ak = PropKit.get("JiMeng.ak"); // 从配置文件获取Access Key
sk = PropKit.get("JiMeng.sk"); // 从配置文件获取Secret Key
static {
// 初始化URL编码器设置不需要编码的字符
int i;
for (i = 97; i <= 122; ++i) {
for (i = 97; i <= 122; ++i) { // a-z
URLENCODER.set(i);
}
for (i = 65; i <= 90; ++i) {
for (i = 65; i <= 90; ++i) { // A-Z
URLENCODER.set(i);
}
for (i = 48; i <= 57; ++i) {
for (i = 48; i <= 57; ++i) { // 0-9
URLENCODER.set(i);
}
URLENCODER.set('-');
@ -73,28 +71,57 @@ public class JmCommon {
URLENCODER.set('~');
}
/**
*
*
* @return "dev"
*/
public static String getEnvPrefix() {
String myEnvVar = System.getenv("WORKING_ENV");
if (myEnvVar == null) {
myEnvVar = "dev"; // 默认为开发环境
}
return myEnvVar;
}
/**
* HTTPAPI
*
* @param method GETPOST
* @param queryList
* @param body
* @param action API
* @return
* @throws Exception
*/
protected static String doRequest(String method, Map<String, String> queryList, byte[] body, String action) throws Exception {
Date date = new Date();
if (body == null) {
body = new byte[0];
}
// 计算请求体的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";
String shortXDate = xDate.substring(0, 8); // 提取日期部分,用于凭证范围
String contentType = "application/json"; // 内容类型
String signHeader = "host;x-date;x-content-sha256;content-type"; // 签名头部列表
// 构建查询参数字符串
SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
realQueryList.put("Action", action);
realQueryList.put("Version", version);
realQueryList.put("Action", action); // 添加Action参数
realQueryList.put("Version", version); // 添加Version参数
StringBuilder querySB = new StringBuilder();
for (String key : realQueryList.keySet()) {
querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
}
querySB.deleteCharAt(querySB.length() - 1);
querySB.deleteCharAt(querySB.length() - 1); // 删除最后一个&符号
// 构建规范请求字符串,用于签名
String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
"host:" + host + "\n" +
"x-date:" + xDate + "\n" +
@ -103,16 +130,25 @@ 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;
// 生成签名密钥并计算签名
byte[] signKey = genSigningSecretKeyV4(shortXDate, region, service);
String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString));
URL url = new URL(schema + "://" + host + path + "?" + querySB);
// 构建URL并创建HTTP连接
URI uri = new URI(schema, "//" + host + path, "?" + querySB.toString());
URL url = uri.toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
// 设置请求头
conn.setRequestProperty("Host", host);
conn.setRequestProperty("X-Date", xDate);
conn.setRequestProperty("X-Content-Sha256", xContentSha256);
@ -121,6 +157,8 @@ public class JmCommon {
" Credential=" + ak + "/" + credentialScope +
", SignedHeaders=" + signHeader +
", Signature=" + signature);
// 如果不是GET请求写入请求体
if (!Objects.equals(conn.getRequestMethod(), "GET")) {
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
@ -128,22 +166,29 @@ public class JmCommon {
os.flush();
os.close();
}
// 建立连接并获取响应
conn.connect();
int responseCode = conn.getResponseCode();
InputStream is;
if (responseCode == 200) {
is = conn.getInputStream();
is = conn.getInputStream(); // 成功响应
} else {
is = conn.getErrorStream();
is = conn.getErrorStream(); // 错误响应
}
// 读取响应内容并关闭流
String responseBody = new String(ByteStreams.toByteArray(is));
is.close();
return responseBody;
}
/**
* URL
*
* @param source
* @return
*/
protected static String signStringEncoder(String source) {
if (source == null) {
return null;
@ -153,10 +198,13 @@ public class JmCommon {
while (bb.hasRemaining()) {
int b = bb.get() & 255;
if (URLENCODER.get(b)) {
// 不需要编码的字符直接添加
buf.append((char) b);
} else if (b == 32) {
// 空格编码为%20
buf.append("%20");
} else {
// 其他字符编码为%XX格式
buf.append("%");
char hex1 = CONST_ENCODE.charAt(b >> 4);
char hex2 = CONST_ENCODE.charAt(b & 15);
@ -168,6 +216,13 @@ public class JmCommon {
return buf.toString();
}
/**
* SHA256
*
* @param content
* @return
* @throws Exception
*/
protected static String hashSHA256(byte[] content) throws Exception {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
@ -177,6 +232,14 @@ public class JmCommon {
}
}
/**
* 使HMAC-SHA256
*
* @param key
* @param content
* @return
* @throws Exception
*/
protected static byte[] hmacSHA256(byte[] key, String content) throws Exception {
try {
Mac mac = Mac.getInstance("HmacSHA256");
@ -187,6 +250,16 @@ public class JmCommon {
}
}
/**
* V4
* 使AWSV4
*
* @param date
* @param region
* @param service
* @return
* @throws Exception
*/
protected static byte[] genSigningSecretKeyV4(String date, String region, String service) throws Exception {
byte[] kDate = hmacSHA256((JmCommon.sk).getBytes(), date);
byte[] kRegion = hmacSHA256(kDate, region);

@ -2,12 +2,18 @@ package com.dsideal.aiSupport.Util.JiMeng;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
public class JmText2Image extends JmCommon {
private static final Logger log = LoggerFactory.getLogger(JmText2Image.class);
private static final String action = "CVProcess";
private static final String req_key = "jimeng_high_aes_general_v21_L";
/**
*
@ -17,9 +23,9 @@ public class JmText2Image extends JmCommon {
*/
public static void generateImage(String prompt, String saveImgPath) throws Exception {
JSONObject req = new JSONObject();
req.put("req_key", "jimeng_high_aes_general_v21_L");
req.put("req_key", req_key);
req.put("prompt", prompt);
String responseBody = doRequest("POST", new HashMap<>(), req.toString().getBytes(), "CVProcess");
String responseBody = doRequest("POST", new HashMap<>(), req.toString().getBytes(), action);
JSONObject jo = JSON.parseObject(responseBody);
String imgBase64 = jo.getJSONObject("data").getJSONArray("binary_data_base64").getFirst().toString();
// 对 Base64 字符串进行解码
@ -29,14 +35,15 @@ public class JmText2Image extends JmCommon {
try (OutputStream os = new FileOutputStream(saveImgPath)) { // 使用-with try-resources 自动关闭资源
os.write(bytes);
os.flush(); // 刷新缓冲区,确保数据写入文件
System.out.println("文件保存成功!");
log.info("文件保存成功!");
} catch (Exception e) {
e.printStackTrace();
log.error("文件保存失败!" + e.getMessage());
}
}
public static void main(String[] args) throws Exception {
String prompt="制作一张vlog视频封面。马卡龙配色美女旅游照片+色块的拼贴画风格主文案是“威海旅游vlog”副文案是“特种兵一日游 被低估的旅游城市”,海报主体是一个穿着短裙、梳双马尾的少女,人物白色描边";
JmText2Image.generateImage(prompt,"d:/Temp/1.jpg");
String prompt = "制作一张vlog视频封面。马卡龙配色美女旅游照片+色块的拼贴画风格主文案是“威海旅游vlog”副文案是“特种兵一日游 被低估的旅游城市”,海报主体是一个穿着短裙、梳双马尾的少女,人物白色描边";
String saveImagePath = "d:/Temp/1.jpg";
JmText2Image.generateImage(prompt, saveImagePath);
}
}

@ -55,3 +55,9 @@ excel:
# 导入excel 的模板配置路径
ExcelImportTemplatePathSuffix: /ExcelImportTemplate/
# 即梦
JiMeng:
# Access Key ID
ak: AKLTZjVlOGU1NzA1YWZkNDExMzkzYzY5YTNlOTRmMTMxODg
# Secret Access Key
sk: WkdabU9UTXdNVEJpTmpWbE5HVTJZVGxtTnpWbU5XSTBaRGN5TW1NMk5tRQ==

Loading…
Cancel
Save