客户管理功能联调
This commit is contained in:
@@ -20,6 +20,7 @@ import com.rj.entity.ImageModel;
|
||||
import com.rj.mapper.ImageModelMapper;
|
||||
import com.rj.service.IImageModelService;
|
||||
import com.rj.service.MinIOService;
|
||||
import com.rj.config.AliyunConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
@@ -59,6 +61,9 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private AliyunConfig aliyunConfig;
|
||||
|
||||
/**
|
||||
* 保存图像模型记录
|
||||
@@ -870,7 +875,7 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
/**
|
||||
* 下载图片到字节数组
|
||||
*
|
||||
* 从指定URL下载图片并返回字节数组
|
||||
* 从指定URL下载图片并返回字节数组,支持超时配置
|
||||
*
|
||||
* @param imageUrl 图片URL
|
||||
* @return 图片字节数组
|
||||
@@ -881,19 +886,36 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
log.info("开始下载图片: {}", imageUrl);
|
||||
|
||||
URL url = new URL(imageUrl);
|
||||
try (InputStream inputStream = url.openStream();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// 设置请求头
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(aliyunConfig.getApi().getConnectTimeout()); // 使用配置的连接超时
|
||||
connection.setReadTimeout(aliyunConfig.getApi().getReadTimeout()); // 使用配置的读取超时
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
connection.setRequestProperty("Accept", "image/*");
|
||||
connection.setRequestProperty("Accept-Encoding", "identity"); // 禁用压缩
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (InputStream inputStream = connection.getInputStream();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
|
||||
byte[] buffer = new byte[8192]; // 增大缓冲区
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
byte[] imageBytes = outputStream.toByteArray();
|
||||
log.info("图片下载完成,大小: {} bytes", imageBytes.length);
|
||||
return imageBytes;
|
||||
}
|
||||
|
||||
byte[] imageBytes = outputStream.toByteArray();
|
||||
log.info("图片下载完成,大小: {} bytes", imageBytes.length);
|
||||
return imageBytes;
|
||||
} else {
|
||||
log.error("下载图片失败,HTTP状态码: {}, URL: {}", responseCode, imageUrl);
|
||||
throw new IOException("HTTP error code: " + responseCode);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("下载图片失败: {}", imageUrl, e);
|
||||
throw new IOException("下载图片失败: " + e.getMessage(), e);
|
||||
@@ -1128,20 +1150,46 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
|
||||
// 2. 上传文件到MinIO并生成临时访问URL
|
||||
log.info("开始上传文件到MinIO,文件名: {}", multipartFile.getOriginalFilename());
|
||||
log.info("文件大小: {} bytes", multipartFile.getSize());
|
||||
log.info("文件类型: {}", multipartFile.getContentType());
|
||||
|
||||
// 生成唯一文件名
|
||||
String originalFilename = multipartFile.getOriginalFilename();
|
||||
String fileExtension = getFileExtension(originalFilename);
|
||||
String uniqueFileName = generateUniqueFileName(fileExtension);
|
||||
|
||||
log.info("生成的文件名: {}", uniqueFileName);
|
||||
log.info("文件扩展名: {}", fileExtension);
|
||||
|
||||
// 上传到MinIO
|
||||
long uploadStartTime = System.currentTimeMillis();
|
||||
String materialUrl = minIOService.uploadFileWithName(multipartFile, uniqueFileName);
|
||||
long uploadEndTime = System.currentTimeMillis();
|
||||
log.info("MinIO上传耗时: {} ms", uploadEndTime - uploadStartTime);
|
||||
|
||||
String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
|
||||
|
||||
log.info("文件上传到MinIO成功:");
|
||||
log.info("永久URL: {}", materialUrl);
|
||||
log.info("临时访问URL: {}", materialTempUrl);
|
||||
|
||||
// 验证临时URL是否可访问
|
||||
log.info("开始验证临时URL可访问性...");
|
||||
try {
|
||||
URL testUrl = new URL(materialTempUrl);
|
||||
HttpURLConnection testConnection = (HttpURLConnection) testUrl.openConnection();
|
||||
testConnection.setRequestMethod("HEAD");
|
||||
testConnection.setConnectTimeout(10000);
|
||||
testConnection.setReadTimeout(10000);
|
||||
int testResponseCode = testConnection.getResponseCode();
|
||||
log.info("临时URL访问测试结果: HTTP {}", testResponseCode);
|
||||
if (testResponseCode != 200) {
|
||||
log.warn("临时URL可能无法访问,这可能导致阿里云API超时");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("临时URL访问测试失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 输出到控制台
|
||||
System.out.println("=== 图生图文件上传信息 ===");
|
||||
System.out.println("原始文件名: " + originalFilename);
|
||||
@@ -1177,11 +1225,38 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
// 5. 使用MultiModalConversation调用阿里云API
|
||||
MultiModalConversation conv = new MultiModalConversation();
|
||||
|
||||
// 构建多模态消息
|
||||
// 构建多模态消息 - 智能选择图片传递方式
|
||||
Object imageContent;
|
||||
|
||||
// 首先尝试使用临时URL
|
||||
if (isUrlAccessible(materialTempUrl)) {
|
||||
log.info("使用临时URL传递图片: {}", materialTempUrl);
|
||||
imageContent = materialTempUrl;
|
||||
}
|
||||
// 如果临时URL不可访问,尝试永久URL
|
||||
else if (isUrlAccessible(materialUrl)) {
|
||||
log.warn("临时URL不可访问,使用永久URL: {}", materialUrl);
|
||||
imageContent = materialUrl;
|
||||
}
|
||||
// 如果URL都不可访问,使用base64编码
|
||||
else {
|
||||
log.warn("所有URL都不可访问,尝试使用base64编码传递图片");
|
||||
try {
|
||||
byte[] imageBytes = multipartFile.getBytes();
|
||||
String base64Image = "data:image/" + getFileExtension(multipartFile.getOriginalFilename()) + ";base64," +
|
||||
java.util.Base64.getEncoder().encodeToString(imageBytes);
|
||||
imageContent = base64Image;
|
||||
log.info("使用base64编码传递图片,大小: {} bytes", imageBytes.length);
|
||||
} catch (Exception e) {
|
||||
log.error("转换为base64失败,回退到使用临时URL: {}", e.getMessage());
|
||||
imageContent = materialTempUrl;
|
||||
}
|
||||
}
|
||||
|
||||
MultiModalMessage userMessage = MultiModalMessage.builder()
|
||||
.role(Role.USER.getValue())
|
||||
.content(Arrays.asList(
|
||||
Collections.singletonMap("image", materialTempUrl), // 使用临时访问URL
|
||||
Collections.singletonMap("image", imageContent),
|
||||
Collections.singletonMap("text", prompt)
|
||||
)).build();
|
||||
|
||||
@@ -1219,9 +1294,57 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
System.out.println("参数: " + JsonUtils.toJson(parametersMap));
|
||||
System.out.println("=========================");
|
||||
|
||||
// 6. 调用阿里云API
|
||||
// 6. 调用阿里云API(带重试机制)
|
||||
log.info("开始调用阿里云图生图API");
|
||||
MultiModalConversationResult conversationResult = conv.call(param);
|
||||
log.info("API配置 - 连接超时: {} ms, 读取超时: {} ms",
|
||||
aliyunConfig.getApi().getConnectTimeout(),
|
||||
aliyunConfig.getApi().getReadTimeout());
|
||||
log.info("重试配置 - 最大重试次数: {}, 重试延迟: {} ms",
|
||||
aliyunConfig.getApi().getMaxRetries(),
|
||||
aliyunConfig.getApi().getRetryDelay());
|
||||
|
||||
MultiModalConversationResult conversationResult = null;
|
||||
int maxRetries = aliyunConfig.getApi().getMaxRetries();
|
||||
int retryCount = 0;
|
||||
|
||||
while (retryCount < maxRetries) {
|
||||
try {
|
||||
log.info("第{}次尝试调用阿里云API...", retryCount + 1);
|
||||
long apiStartTime = System.currentTimeMillis();
|
||||
|
||||
conversationResult = conv.call(param);
|
||||
|
||||
long apiEndTime = System.currentTimeMillis();
|
||||
log.info("阿里云API调用成功,耗时: {} ms", apiEndTime - apiStartTime);
|
||||
break; // 成功则跳出循环
|
||||
|
||||
} catch (ApiException e) {
|
||||
retryCount++;
|
||||
log.error("阿里云API调用失败,第{}次尝试,错误详情:", retryCount);
|
||||
log.error("错误代码: {}", e.getMessage());
|
||||
log.error("请求ID: {}", extractRequestId(e.getMessage()));
|
||||
|
||||
if (e.getMessage().contains("DataInspection") || e.getMessage().contains("timeout")) {
|
||||
if (retryCount < maxRetries) {
|
||||
long delayTime = aliyunConfig.getApi().getRetryDelay() * retryCount;
|
||||
log.warn("检测到超时错误,{}ms后进行第{}次重试", delayTime, retryCount + 1);
|
||||
try {
|
||||
Thread.sleep(delayTime);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("重试被中断", ie);
|
||||
}
|
||||
} else {
|
||||
log.error("阿里云API调用失败,已达到最大重试次数: {}", maxRetries);
|
||||
log.error("最终失败原因: {}", e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
log.error("非超时错误,直接抛出异常: {}", e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 输出完整响应到控制台
|
||||
System.out.println("=== 阿里云API完整响应 ===");
|
||||
@@ -1358,4 +1481,49 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
return "req_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从错误消息中提取请求ID
|
||||
*
|
||||
* @param errorMessage 错误消息
|
||||
* @return 请求ID,如果未找到则返回"未知"
|
||||
*/
|
||||
private String extractRequestId(String errorMessage) {
|
||||
try {
|
||||
if (errorMessage != null && errorMessage.contains("requestId")) {
|
||||
int startIndex = errorMessage.indexOf("\"requestId\":\"") + 13;
|
||||
int endIndex = errorMessage.indexOf("\"", startIndex);
|
||||
if (startIndex > 12 && endIndex > startIndex) {
|
||||
return errorMessage.substring(startIndex, endIndex);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("提取请求ID失败: {}", e.getMessage());
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查URL是否可访问
|
||||
*
|
||||
* @param urlString URL字符串
|
||||
* @return 如果URL可访问返回true,否则返回false
|
||||
*/
|
||||
private boolean isUrlAccessible(String urlString) {
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setConnectTimeout(5000); // 5秒连接超时
|
||||
connection.setReadTimeout(5000); // 5秒读取超时
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
log.info("URL访问测试: {} -> HTTP {}", urlString, responseCode);
|
||||
return responseCode == 200;
|
||||
} catch (Exception e) {
|
||||
log.warn("URL访问测试失败: {} -> {}", urlString, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user