客户管理功能联调

This commit is contained in:
spllzh
2025-10-24 10:41:48 +08:00
parent 2b9d14cc2e
commit 6801f06db5
27 changed files with 411 additions and 145 deletions

View File

@@ -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;
}
}
}