图生图
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.rj.service.impl;
|
||||
|
||||
import ai.djl.util.JsonUtils;
|
||||
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
|
||||
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam;
|
||||
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
|
||||
@@ -13,6 +12,7 @@ import com.alibaba.dashscope.exception.ApiException;
|
||||
import com.alibaba.dashscope.exception.NoApiKeyException;
|
||||
import com.alibaba.dashscope.exception.UploadFileException;
|
||||
import com.alibaba.dashscope.utils.Constants;
|
||||
import com.alibaba.dashscope.utils.JsonUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.rj.controller.TextModelController;
|
||||
@@ -24,11 +24,14 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 图像模型服务实现类
|
||||
@@ -53,6 +56,9 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
|
||||
@Autowired
|
||||
private MinIOService minIOService;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 保存图像模型记录
|
||||
@@ -1085,4 +1091,271 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图生图
|
||||
*
|
||||
* 根据图片和指令生成新图片,包括:
|
||||
* - 验证API Key和参数
|
||||
* - 构建请求体
|
||||
* - 调用阿里云图生图API
|
||||
* - 处理异步响应
|
||||
* - 返回任务信息
|
||||
*
|
||||
* @param multipartFile 上传的图片文件
|
||||
|
||||
* @param ownerName 所属人姓名
|
||||
* @param ownerPhone 所属人电话
|
||||
* @param imageName 图片名称
|
||||
* @param model 模型名称,默认为wanx-v1
|
||||
* @param parameters 参数字符串(JSON格式)
|
||||
* @return 生成结果,包含任务ID等信息
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> generateImageToImage(MultipartFile multipartFile, String prompt,
|
||||
String ownerName, String ownerPhone, String imageName,
|
||||
String model, String parameters) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
log.info("开始图生图处理,ownerName: {}, imageName: {}, refPrompt: {}",
|
||||
ownerName, imageName, prompt);
|
||||
|
||||
// 1. 验证API Key
|
||||
String apiKey = System.getenv("DASHSCOPE_API_KEY");
|
||||
if (apiKey == null || apiKey.isEmpty()) {
|
||||
throw new RuntimeException("DASHSCOPE_API_KEY 环境变量未设置");
|
||||
}
|
||||
|
||||
// 2. 上传文件到MinIO并生成临时访问URL
|
||||
log.info("开始上传文件到MinIO,文件名: {}", multipartFile.getOriginalFilename());
|
||||
|
||||
// 生成唯一文件名
|
||||
String originalFilename = multipartFile.getOriginalFilename();
|
||||
String fileExtension = getFileExtension(originalFilename);
|
||||
String uniqueFileName = generateUniqueFileName(fileExtension);
|
||||
|
||||
// 上传到MinIO
|
||||
String materialUrl = minIOService.uploadFileWithName(multipartFile, uniqueFileName);
|
||||
String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
|
||||
|
||||
log.info("文件上传到MinIO成功:");
|
||||
log.info("永久URL: {}", materialUrl);
|
||||
log.info("临时访问URL: {}", materialTempUrl);
|
||||
|
||||
// 输出到控制台
|
||||
System.out.println("=== 图生图文件上传信息 ===");
|
||||
System.out.println("原始文件名: " + originalFilename);
|
||||
System.out.println("生成的文件名: " + uniqueFileName);
|
||||
System.out.println("MinIO永久URL: " + materialUrl);
|
||||
System.out.println("MinIO临时访问URL: " + materialTempUrl);
|
||||
System.out.println("=========================");
|
||||
|
||||
// 3. 创建ImageModel记录并保存到数据库
|
||||
ImageModel imageModel = new ImageModel();
|
||||
imageModel.setImageName(imageName != null ? imageName : originalFilename);
|
||||
imageModel.setOwnerName(ownerName);
|
||||
imageModel.setOwnerPhone(ownerPhone);
|
||||
imageModel.setImageType("material");
|
||||
imageModel.setPrompt(prompt);
|
||||
imageModel.setModelName(model);
|
||||
imageModel.setMaterialUrl(materialUrl);
|
||||
imageModel.setMaterialTempUrl(materialTempUrl);
|
||||
imageModel.setCreateTime(LocalDateTime.now());
|
||||
imageModel.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 保存到数据库
|
||||
boolean saveResult = this.saveImageModel(imageModel);
|
||||
if (!saveResult) {
|
||||
throw new RuntimeException("保存图生图记录失败");
|
||||
}
|
||||
|
||||
log.info("图生图记录已保存到数据库,ID: {}", imageModel.getUuid());
|
||||
|
||||
// 4. 设置API基础URL
|
||||
Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
|
||||
|
||||
// 5. 使用MultiModalConversation调用阿里云API
|
||||
MultiModalConversation conv = new MultiModalConversation();
|
||||
|
||||
// 构建多模态消息
|
||||
MultiModalMessage userMessage = MultiModalMessage.builder()
|
||||
.role(Role.USER.getValue())
|
||||
.content(Arrays.asList(
|
||||
Collections.singletonMap("image", materialTempUrl), // 使用临时访问URL
|
||||
Collections.singletonMap("text", prompt)
|
||||
)).build();
|
||||
|
||||
// 解析parameters参数
|
||||
Map<String, Object> parametersMap = new HashMap<>();
|
||||
if (parameters != null && !parameters.isEmpty()) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> parsedParams = objectMapper.readValue(parameters, Map.class);
|
||||
parametersMap = parsedParams;
|
||||
} catch (Exception e) {
|
||||
log.warn("解析parameters参数失败,使用默认值: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认参数
|
||||
parametersMap.put("watermark", false);
|
||||
if (!parametersMap.containsKey("negative_prompt")) {
|
||||
parametersMap.put("negative_prompt", " ");
|
||||
}
|
||||
|
||||
// 构建API参数
|
||||
MultiModalConversationParam param = MultiModalConversationParam.builder()
|
||||
.apiKey(apiKey)
|
||||
.model(model) // 使用图生图模型
|
||||
.messages(Collections.singletonList(userMessage))
|
||||
.parameters(parametersMap)
|
||||
.build();
|
||||
|
||||
// 输出请求参数到控制台
|
||||
System.out.println("=== 发送给阿里云的请求参数 ===");
|
||||
System.out.println("模型: qwen-image-edit");
|
||||
System.out.println("图片URL: " + materialTempUrl);
|
||||
System.out.println("提示词: " + prompt);
|
||||
System.out.println("参数: " + JsonUtils.toJson(parametersMap));
|
||||
System.out.println("=========================");
|
||||
|
||||
// 6. 调用阿里云API
|
||||
log.info("开始调用阿里云图生图API");
|
||||
MultiModalConversationResult conversationResult = conv.call(param);
|
||||
|
||||
// 输出完整响应到控制台
|
||||
System.out.println("=== 阿里云API完整响应 ===");
|
||||
System.out.println(JsonUtils.toJson(conversationResult));
|
||||
System.out.println("======================");
|
||||
|
||||
// 7. 处理生成结果
|
||||
if (conversationResult != null && conversationResult.getOutput() != null &&
|
||||
conversationResult.getOutput().getChoices() != null &&
|
||||
!conversationResult.getOutput().getChoices().isEmpty()) {
|
||||
|
||||
log.info("图生图API调用成功,开始处理结果");
|
||||
|
||||
// 从多模态对话结果中提取图像URL
|
||||
String generatedImageUrl = null;
|
||||
try {
|
||||
var choices = conversationResult.getOutput().getChoices();
|
||||
if (!choices.isEmpty()) {
|
||||
var message = choices.get(0).getMessage();
|
||||
var content = message.getContent();
|
||||
|
||||
log.info("API返回的content: {}", JsonUtils.toJson(content));
|
||||
|
||||
// 解析content数组中的image字段
|
||||
if (content != null && !content.isEmpty()) {
|
||||
for (Object contentItem : content) {
|
||||
if (contentItem instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> contentMap = (Map<String, Object>) contentItem;
|
||||
if (contentMap.containsKey("image")) {
|
||||
generatedImageUrl = (String) contentMap.get("image");
|
||||
log.info("提取到生成图像URL: {}", generatedImageUrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (generatedImageUrl == null || generatedImageUrl.trim().isEmpty()) {
|
||||
log.warn("未能从API返回结果中提取图像URL");
|
||||
throw new RuntimeException("未能从API返回结果中提取图像URL");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析API返回结果失败", e);
|
||||
throw new RuntimeException("解析API返回结果失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 8. 下载生成的图片并上传到MinIO
|
||||
if (generatedImageUrl != null && !generatedImageUrl.trim().isEmpty()) {
|
||||
try {
|
||||
log.info("开始下载生成的图片: {}", generatedImageUrl);
|
||||
|
||||
// 下载图片到字节数组
|
||||
byte[] imageBytes = downloadImageToBytes(generatedImageUrl);
|
||||
log.info("图片下载成功,大小: {} bytes", imageBytes.length);
|
||||
|
||||
// 生成唯一文件名
|
||||
String resultFileName = generateUniqueFileName("png");
|
||||
|
||||
// 上传到MinIO
|
||||
String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/png");
|
||||
log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
|
||||
|
||||
// 生成7天临时访问链接
|
||||
String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
|
||||
log.info("生成7天临时访问链接: {}", resultImageTempUrl);
|
||||
|
||||
// 更新ImageModel对象
|
||||
imageModel.setResultImageUrl(resultImageMinIOUrl);
|
||||
imageModel.setResultImageTempUrl(resultImageTempUrl);
|
||||
imageModel.setUpdateTime(LocalDateTime.now());
|
||||
imageModel.setImageType("result");
|
||||
// 更新数据库记录
|
||||
boolean updateResult = this.updateById(imageModel);
|
||||
if (!updateResult) {
|
||||
log.error("更新图生图结果记录失败");
|
||||
} else {
|
||||
log.info("图生图结果已更新到数据库");
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
result.put("success", true);
|
||||
result.put("message", "图生图处理完成");
|
||||
result.put("imageCount", 1);
|
||||
result.put("imageUrl", resultImageTempUrl);
|
||||
result.put("imageMinIOUrl", resultImageMinIOUrl);
|
||||
result.put("originalImageUrl", materialTempUrl);
|
||||
result.put("prompt", model);
|
||||
result.put("model", model);
|
||||
result.put("requestId", imageModel.getUuid());
|
||||
result.put("timestamp", LocalDateTime.now());
|
||||
|
||||
log.info("✅ 图生图处理完成,结果已保存到数据库,ID: {}", imageModel.getUuid());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理生成的图片失败", e);
|
||||
throw new RuntimeException("处理生成的图片失败: " + e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
log.warn("生成的图片URL为空");
|
||||
throw new RuntimeException("生成的图片URL为空");
|
||||
}
|
||||
} else {
|
||||
log.warn("图生图结果为空");
|
||||
throw new RuntimeException("图生图结果为空");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (ApiException | NoApiKeyException | UploadFileException e) {
|
||||
log.error("阿里云API调用失败", e);
|
||||
throw new RuntimeException("阿里云API调用失败: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
log.error("图生图处理失败: {}", e.getMessage(), e);
|
||||
|
||||
result.put("success", false);
|
||||
result.put("message", "图生图处理失败: " + e.getMessage());
|
||||
result.put("error", e.getClass().getSimpleName());
|
||||
result.put("timestamp", LocalDateTime.now());
|
||||
result.put("requestId", generateRequestId());
|
||||
|
||||
throw new RuntimeException("图生图处理失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成请求ID
|
||||
*
|
||||
* @return 唯一的请求ID
|
||||
*/
|
||||
private String generateRequestId() {
|
||||
return "req_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user