From 6cec8cf5800a8d16daa00a0b9340b42283b30d61 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Tue, 2 Sep 2025 16:04:10 +0800 Subject: [PATCH] 'commit' --- .../Ai/Util/Liblib/Kit/LibLibCommon.java | 84 +++--- dsLightRag/Liblib/LibLibCommon.java | 249 ++++++++++++++++++ dsLightRag/Liblib/T1_Test.py | 45 ++++ dsLightRag/Liblib/T1_VersionGet.py | 103 ++++++-- 4 files changed, 417 insertions(+), 64 deletions(-) create mode 100644 dsLightRag/Liblib/LibLibCommon.java create mode 100644 dsLightRag/Liblib/T1_Test.py diff --git a/dsAi/src/main/java/com/dsideal/Ai/Util/Liblib/Kit/LibLibCommon.java b/dsAi/src/main/java/com/dsideal/Ai/Util/Liblib/Kit/LibLibCommon.java index 01f317fc..249789e8 100644 --- a/dsAi/src/main/java/com/dsideal/Ai/Util/Liblib/Kit/LibLibCommon.java +++ b/dsAi/src/main/java/com/dsideal/Ai/Util/Liblib/Kit/LibLibCommon.java @@ -11,6 +11,7 @@ import javax.crypto.spec.SecretKeySpec; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.jfinal.kit.StrKit; import lombok.Getter; import okhttp3.*; import org.apache.commons.codec.binary.Base64; @@ -24,8 +25,8 @@ public class LibLibCommon { // API基础URL protected static final String API_BASE_URL = "https://openapi.liblibai.cloud"; // API访问凭证 - protected static final String accessKey="sOCtVLVTNOZkRMajlhzCmg"; // Access Key - protected static final String secretKey="PUe8QTRG9i0G9EbpedHmIpLQ0FyxoYY9"; // Secret Key + protected static final String accessKey = "sOCtVLVTNOZkRMajlhzCmg"; // Access Key + protected static final String secretKey = "PUe8QTRG9i0G9EbpedHmIpLQ0FyxoYY9"; // Secret Key // 查询任务状态API路径 protected static final String QUERY_STATUS_PATH = "/api/generate/webui/status"; // 日志 @@ -46,9 +47,10 @@ public class LibLibCommon { this.signatureNonce = signatureNonce; } } - + /** * 创建OkHttpClient实例 + * * @return OkHttpClient实例 */ protected static OkHttpClient createHttpClient() { @@ -58,19 +60,25 @@ public class LibLibCommon { .writeTimeout(60, TimeUnit.SECONDS) .build(); } - + /** * 生成完整的签名信息,包括签名、时间戳和随机字符串 + * * @param uri API接口的uri地址 * @return 签名信息对象 */ public static SignatureInfo sign(String uri) { + return sign(uri, 0, null); + } + + public static SignatureInfo sign(String uri, long timestamp, String signatureNonce) { // 当前毫秒时间戳 - long timestamp = System.currentTimeMillis(); + if (timestamp == 0) timestamp = System.currentTimeMillis(); // 随机字符串 - String signatureNonce = RandomStringUtils.randomAlphanumeric(10); + if (StrKit.isBlank(signatureNonce)) signatureNonce = RandomStringUtils.randomAlphanumeric(10); // 拼接请求数据 String content = uri + "&" + timestamp + "&" + signatureNonce; + System.out.println(content); try { // 生成签名 SecretKeySpec secret = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); @@ -84,9 +92,10 @@ public class LibLibCommon { throw new RuntimeException(e); } } - + /** * 清理URL,移除可能的反引号和多余空格 + * * @param url 原始URL * @return 清理后的URL */ @@ -96,10 +105,11 @@ public class LibLibCommon { } return url.trim().replace("`", ""); } - + /** * 构建带签名的URL - * @param uri API路径 + * + * @param uri API路径 * @param signInfo 签名信息 * @return 构建好的HttpUrl.Builder */ @@ -110,47 +120,48 @@ public class LibLibCommon { .addQueryParameter("Timestamp", String.valueOf(signInfo.getTimestamp())) .addQueryParameter("SignatureNonce", signInfo.getSignatureNonce()); } - + /** * 发送HTTP请求并处理响应 - * @param request HTTP请求 + * + * @param request HTTP请求 * @param logPrefix 日志前缀 * @return 响应的JSON对象 * @throws IOException 异常信息 */ protected static JSONObject sendRequest(Request request, String logPrefix) throws IOException { OkHttpClient client = createHttpClient(); - + // 执行请求 log.info("{}: {}", logPrefix, request.url()); Response response = client.newCall(request).execute(); - + // 处理响应 if (!response.isSuccessful()) { String errorMsg = logPrefix + "失败,状态码: " + response.code(); log.error(errorMsg); throw new IOException(errorMsg); } - + // 解析响应 String responseBody = response.body().string(); log.info("{}响应: {}", logPrefix, responseBody); - + JSONObject responseJson = JSON.parseObject(responseBody); int code = responseJson.getIntValue("code"); - + if (code != 0) { String errorMsg = logPrefix + "失败,错误码: " + code + ", 错误信息: " + responseJson.getString("msg"); log.error(errorMsg); throw new IOException(errorMsg); } - + return responseJson; } - + /** * 查询生图任务结果 - * + * * @param generateUuid 生图任务UUID * @return 任务结果信息 * @throws IOException 异常信息 @@ -159,16 +170,16 @@ public class LibLibCommon { // 构建请求体 JSONObject requestBody = new JSONObject(); requestBody.put("generateUuid", generateUuid); - + // 获取API路径 String uri = QUERY_STATUS_PATH; - + // 生成签名信息 SignatureInfo signInfo = sign(uri); - + // 构建带签名的URL HttpUrl.Builder urlBuilder = buildSignedUrl(uri, signInfo); - + // 创建请求 MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString()); @@ -177,16 +188,16 @@ public class LibLibCommon { .method("POST", body) .addHeader("Content-Type", "application/json") .build(); - + // 发送请求并获取响应 JSONObject responseJson = sendRequest(request, "查询生图任务结果"); - + return responseJson.getJSONObject("data"); } - + /** * 获取生成图片的URL列表 - * + * * @param generateUuid 生图任务UUID * @return 图片URL列表 * @throws IOException 异常信息 @@ -194,7 +205,7 @@ public class LibLibCommon { public static List getGeneratedImageUrls(String generateUuid) throws IOException { JSONObject resultData = queryTaskResult(generateUuid); List imageUrls = new ArrayList<>(); - + // 检查生成状态 int generateStatus = resultData.getIntValue("generateStatus"); if (generateStatus == 5) { // 5表示生成成功 @@ -210,26 +221,27 @@ public class LibLibCommon { } } } else { - log.info("生图任务尚未完成,当前状态: {}, 完成百分比: {}%", + log.info("生图任务尚未完成,当前状态: {}, 完成百分比: {}%", generateStatus, resultData.getIntValue("percentCompleted")); } - + return imageUrls; } - + /** * 创建通用的HTTP请求 - * @param uri API路径 + * + * @param uri API路径 * @param requestBody 请求体JSON对象 * @return 构建好的Request对象 */ protected static Request createRequest(String uri, JSONObject requestBody) { // 生成签名信息 SignatureInfo signInfo = sign(uri); - + // 构建带签名的URL HttpUrl.Builder urlBuilder = buildSignedUrl(uri, signInfo); - + // 创建请求 MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString()); @@ -242,8 +254,8 @@ public class LibLibCommon { public static void main(String[] args) { String uri = "https://openapi.liblibai.cloud/api/model/version/get"; - SignatureInfo signInfo = sign(uri); + SignatureInfo signInfo = sign(uri, 1756799766502L, "K91nkXyrCH"); - System.out.println(signInfo.toString()); + System.out.println(signInfo.getSignature()); } } \ No newline at end of file diff --git a/dsLightRag/Liblib/LibLibCommon.java b/dsLightRag/Liblib/LibLibCommon.java new file mode 100644 index 00000000..01f317fc --- /dev/null +++ b/dsLightRag/Liblib/LibLibCommon.java @@ -0,0 +1,249 @@ +package com.dsideal.Ai.Util.Liblib.Kit; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import okhttp3.*; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class LibLibCommon { + // API基础URL + protected static final String API_BASE_URL = "https://openapi.liblibai.cloud"; + // API访问凭证 + protected static final String accessKey="sOCtVLVTNOZkRMajlhzCmg"; // Access Key + protected static final String secretKey="PUe8QTRG9i0G9EbpedHmIpLQ0FyxoYY9"; // Secret Key + // 查询任务状态API路径 + protected static final String QUERY_STATUS_PATH = "/api/generate/webui/status"; + // 日志 + private static final Logger log = LoggerFactory.getLogger(LibLibCommon.class); + + /** + * 签名信息类,包含签名、时间戳和随机字符串 + */ + @Getter + public static class SignatureInfo { + private final String signature; + private final long timestamp; + private final String signatureNonce; + + public SignatureInfo(String signature, long timestamp, String signatureNonce) { + this.signature = signature; + this.timestamp = timestamp; + this.signatureNonce = signatureNonce; + } + } + + /** + * 创建OkHttpClient实例 + * @return OkHttpClient实例 + */ + protected static OkHttpClient createHttpClient() { + return new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .build(); + } + + /** + * 生成完整的签名信息,包括签名、时间戳和随机字符串 + * @param uri API接口的uri地址 + * @return 签名信息对象 + */ + public static SignatureInfo sign(String uri) { + // 当前毫秒时间戳 + long timestamp = System.currentTimeMillis(); + // 随机字符串 + String signatureNonce = RandomStringUtils.randomAlphanumeric(10); + // 拼接请求数据 + String content = uri + "&" + timestamp + "&" + signatureNonce; + try { + // 生成签名 + SecretKeySpec secret = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(secret); + String signature = Base64.encodeBase64URLSafeString(mac.doFinal(content.getBytes())); + return new SignatureInfo(signature, timestamp, signatureNonce); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("no such algorithm"); + } catch (InvalidKeyException e) { + throw new RuntimeException(e); + } + } + + /** + * 清理URL,移除可能的反引号和多余空格 + * @param url 原始URL + * @return 清理后的URL + */ + protected static String cleanUrl(String url) { + if (url == null || url.isEmpty()) { + return url; + } + return url.trim().replace("`", ""); + } + + /** + * 构建带签名的URL + * @param uri API路径 + * @param signInfo 签名信息 + * @return 构建好的HttpUrl.Builder + */ + protected static HttpUrl.Builder buildSignedUrl(String uri, SignatureInfo signInfo) { + return HttpUrl.parse(API_BASE_URL + uri).newBuilder() + .addQueryParameter("AccessKey", accessKey) + .addQueryParameter("Signature", signInfo.getSignature()) + .addQueryParameter("Timestamp", String.valueOf(signInfo.getTimestamp())) + .addQueryParameter("SignatureNonce", signInfo.getSignatureNonce()); + } + + /** + * 发送HTTP请求并处理响应 + * @param request HTTP请求 + * @param logPrefix 日志前缀 + * @return 响应的JSON对象 + * @throws IOException 异常信息 + */ + protected static JSONObject sendRequest(Request request, String logPrefix) throws IOException { + OkHttpClient client = createHttpClient(); + + // 执行请求 + log.info("{}: {}", logPrefix, request.url()); + Response response = client.newCall(request).execute(); + + // 处理响应 + if (!response.isSuccessful()) { + String errorMsg = logPrefix + "失败,状态码: " + response.code(); + log.error(errorMsg); + throw new IOException(errorMsg); + } + + // 解析响应 + String responseBody = response.body().string(); + log.info("{}响应: {}", logPrefix, responseBody); + + JSONObject responseJson = JSON.parseObject(responseBody); + int code = responseJson.getIntValue("code"); + + if (code != 0) { + String errorMsg = logPrefix + "失败,错误码: " + code + ", 错误信息: " + responseJson.getString("msg"); + log.error(errorMsg); + throw new IOException(errorMsg); + } + + return responseJson; + } + + /** + * 查询生图任务结果 + * + * @param generateUuid 生图任务UUID + * @return 任务结果信息 + * @throws IOException 异常信息 + */ + public static JSONObject queryTaskResult(String generateUuid) throws IOException { + // 构建请求体 + JSONObject requestBody = new JSONObject(); + requestBody.put("generateUuid", generateUuid); + + // 获取API路径 + String uri = QUERY_STATUS_PATH; + + // 生成签名信息 + SignatureInfo signInfo = sign(uri); + + // 构建带签名的URL + HttpUrl.Builder urlBuilder = buildSignedUrl(uri, signInfo); + + // 创建请求 + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString()); + Request request = new Request.Builder() + .url(urlBuilder.build()) + .method("POST", body) + .addHeader("Content-Type", "application/json") + .build(); + + // 发送请求并获取响应 + JSONObject responseJson = sendRequest(request, "查询生图任务结果"); + + return responseJson.getJSONObject("data"); + } + + /** + * 获取生成图片的URL列表 + * + * @param generateUuid 生图任务UUID + * @return 图片URL列表 + * @throws IOException 异常信息 + */ + public static List getGeneratedImageUrls(String generateUuid) throws IOException { + JSONObject resultData = queryTaskResult(generateUuid); + List imageUrls = new ArrayList<>(); + + // 检查生成状态 + int generateStatus = resultData.getIntValue("generateStatus"); + if (generateStatus == 5) { // 5表示生成成功 + if (resultData.containsKey("images")) { + for (Object imageObj : resultData.getJSONArray("images")) { + JSONObject imageJson = (JSONObject) imageObj; + String imageUrl = imageJson.getString("imageUrl"); + if (imageUrl != null && !imageUrl.isEmpty()) { + // 清理URL + imageUrl = cleanUrl(imageUrl); + imageUrls.add(imageUrl); + } + } + } + } else { + log.info("生图任务尚未完成,当前状态: {}, 完成百分比: {}%", + generateStatus, resultData.getIntValue("percentCompleted")); + } + + return imageUrls; + } + + /** + * 创建通用的HTTP请求 + * @param uri API路径 + * @param requestBody 请求体JSON对象 + * @return 构建好的Request对象 + */ + protected static Request createRequest(String uri, JSONObject requestBody) { + // 生成签名信息 + SignatureInfo signInfo = sign(uri); + + // 构建带签名的URL + HttpUrl.Builder urlBuilder = buildSignedUrl(uri, signInfo); + + // 创建请求 + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString()); + return new Request.Builder() + .url(urlBuilder.build()) + .method("POST", body) + .addHeader("Content-Type", "application/json") + .build(); + } + + public static void main(String[] args) { + String uri = "https://openapi.liblibai.cloud/api/model/version/get"; + SignatureInfo signInfo = sign(uri); + + System.out.println(signInfo.toString()); + } +} \ No newline at end of file diff --git a/dsLightRag/Liblib/T1_Test.py b/dsLightRag/Liblib/T1_Test.py new file mode 100644 index 00000000..299f308e --- /dev/null +++ b/dsLightRag/Liblib/T1_Test.py @@ -0,0 +1,45 @@ +import hashlib + +import requests +import json +import hmac +from hashlib import sha1 +import base64 +import time +import string +import secrets + +from Config.Config import LIBLIB_SECRETKEY, LIBLIB_URL, LIBLIB_ACCESSKEY + + +class SignatureInfo: + """签名信息封装类,对应Java的SignatureInfo类""" + + def __init__(self, signature: str, timestamp: int, signature_nonce: str): + self.signature = signature + self.timestamp = timestamp + self.signature_nonce = signature_nonce + + def __repr__(self) -> str: + return f"SignatureInfo(signature='{self.signature}', timestamp={self.timestamp}, signature_nonce='{self.signature_nonce}')" + + +def make_sign(uri, timestamp, signatureNonce): + # 当前毫秒时间戳(修正:使用整数类型) + if timestamp == 0: + timestamp = int(time.time() * 1000) + if signatureNonce is None: + signatureNonce = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(10)) + content = f"{uri}&{timestamp}&{signatureNonce}" + print(content) + signature = hmac.new(LIBLIB_SECRETKEY.encode('utf-8'), content.encode('utf-8'), digestmod=hashlib.sha1).digest() + signature = base64.urlsafe_b64encode(signature).decode('utf-8').strip() + return SignatureInfo(signature, timestamp, signatureNonce) + + +# 请求API接口的uri地址(修正:使用相对路径,不包含域名) +uri = f"/api/model/version/get" +# 生成签名信息(确保在URL构建前调用) +signature_info = make_sign(LIBLIB_URL+uri,1756799766502,'K91nkXyrCH') # 使用API_PATH而非完整URL + +print(signature_info) diff --git a/dsLightRag/Liblib/T1_VersionGet.py b/dsLightRag/Liblib/T1_VersionGet.py index 8d5b0ae8..5a0e8f5f 100644 --- a/dsLightRag/Liblib/T1_VersionGet.py +++ b/dsLightRag/Liblib/T1_VersionGet.py @@ -1,51 +1,98 @@ +import hashlib + import requests import json import hmac from hashlib import sha1 import base64 import time -import uuid +import string +import secrets from Config.Config import LIBLIB_SECRETKEY, LIBLIB_URL, LIBLIB_ACCESSKEY +class SignatureInfo: + """签名信息封装类,对应Java的SignatureInfo类""" + def __init__(self, signature: str, timestamp: int, signature_nonce: str): + self.signature = signature + self.timestamp = timestamp + self.signature_nonce = signature_nonce + + def __repr__(self) -> str: + return f"SignatureInfo(signature='{self.signature}', timestamp={self.timestamp}, signature_nonce='{self.signature_nonce}')" + + def make_sign(uri): - """ - 生成签名 - """ - # 当前毫秒时间戳 - timestamp = str(int(time.time() * 1000)) - # 随机字符串 - signature_nonce = str(uuid.uuid4()) - # 拼接请求数据 - content = '&'.join((uri, timestamp, signature_nonce)) - # 生成签名 - digest = hmac.new(LIBLIB_SECRETKEY.encode(), content.encode(), sha1).digest() - # 移除为了补全base64位数而填充的尾部等号 - sign = base64.urlsafe_b64encode(digest).rstrip(b'=').decode() - return sign, timestamp, signature_nonce + # 当前毫秒时间戳(修正:使用整数类型) + timestamp = int(time.time() * 1000) + # 生成10位字母数字随机字符串(修正:匹配Java的randomAlphanumeric) + signature_nonce = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(10)) + # 拼接签名内容(修正:使用Java相同的顺序和分隔符) + content = f"{uri}&{timestamp}&{signature_nonce}" + # HMAC-SHA1签名(修正:确保编码一致) + signature = hmac.new(LIBLIB_SECRETKEY.encode('utf-8'), content.encode('utf-8'), digestmod=hashlib.sha1).digest() + # Base64 URL安全编码(修正:使用URL安全编码) + signature = base64.urlsafe_b64encode(signature).decode('utf-8').strip() + print(f"签名调试信息:\nURI: {uri}\nTimestamp: {timestamp}\nNonce: {signature_nonce}\nContent: {content}\nSignature: {signature}") + return SignatureInfo(signature, timestamp, signature_nonce) -# 请求API接口的uri地址 -uri = f"{LIBLIB_URL}/api/model/version/get" -Signature, timestamp, signature_nonce = make_sign(uri) +# 请求API接口的uri地址(修正:使用相对路径,不包含域名) +uri = f"/api/model/version/get" +# 生成签名信息(确保在URL构建前调用) +signature_info = make_sign(uri) # 使用API_PATH而非完整URL -print(Signature) -print(timestamp) -print(signature_nonce) +# 构建完整URL(修正:此处才拼接基础URL) +# API配置(确保以下常量已定义) +LIBLIB_URL = "https://openapi.liblibai.cloud" +API_PATH = '/api/model/version/get' +LIBLIB_ACCESSKEY = 'sOCtVLVTNOZkRMajlhzCmg' # 从Java代码同步的AccessKey +version_uuid = 'YOUR_VERSION_UUID' # 替换为实际UUID +# 构建完整URL(修正:使用signature_info对象属性) +full_url = f"{LIBLIB_URL}{API_PATH}?version_uuid={version_uuid}&AccessKey={LIBLIB_ACCESSKEY}&Signature={signature_info.signature}&Timestamp={signature_info.timestamp}&SignatureNonce={signature_info.signature_nonce}" -url = f"{uri}?AccessKey={LIBLIB_ACCESSKEY}&Signature={Signature}&Timestamp={timestamp}&SignatureNonce={signature_nonce}" - -# 设置请求头 +# 定义请求头 headers = {"Content-Type": "application/json"} + +# 定义请求体 version_uuid = "4bb1335feb1e4d2eafe5a77bb93e861f" -# 准备请求体数据 request_body = {"version_uuid": version_uuid} +# 发送请求(使用正确的full_url变量) +response = requests.post(full_url, headers=headers, json=request_body) + +# 添加详细调试输出 +#print(f"请求URL: {url}") +# 修正:在使用headers前定义请求头 +headers = {"Content-Type": "application/json"} + +# 定义version_uuid变量(请替换为实际的UUID值) +version_uuid = "4bb1335feb1e4d2eafe5a77bb93e861f" + +# 构建请求体 +request_body = {"version_uuid": version_uuid} +print(f"请求头: {headers}") +print(f"请求体: {json.dumps(request_body)}") + try: - # 发送POST请求 - response = requests.post(url, headers=headers, data=json.dumps(request_body)) - response.raise_for_status() # 检查请求是否成功 + # 修改请求方法为POST并添加完整参数 + response = requests.post(LIBLIB_URL+uri, headers=headers, json=request_body) + + # 增加详细调试输出 + print(f"完整请求URL: {LIBLIB_URL}{uri}") + print(f"请求方法: POST") + print(f"请求头: {headers}") + print(f"请求体: {json.dumps(request_body, ensure_ascii=False)}") + print(f"响应状态码: {response.status_code}") + print(f"响应内容: {response.text}") + + # 验证version_uuid有效性(请替换为实际有效的UUID) + version_uuid = "有效的模型版本UUID" + print(f"请求体: {json.dumps(request_body)}") + print(f"响应状态码: {response.status_code}") + print(f"响应内容: {response.text}") # 打印完整响应内容 + response.raise_for_status() result = response.json() print(result.get("code")) print(result.get("msg"))