文本生成图片
This commit is contained in:
@@ -173,6 +173,8 @@ public class PasswordUtil {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -157,6 +157,8 @@ public class ServiceManager {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ public class AliyunConfig {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -678,6 +678,31 @@ public class ImageModelController {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/image-gen-byText")
|
||||
@Operation(summary = "文本生成图像", description = "基于文本提示词生成图像")
|
||||
public ResponseEntity<Map<String, Object>> imageGen(
|
||||
@Parameter(description = "文本生成图像") @Valid @RequestBody TextModelController.ImageProcessingRequest request) {
|
||||
log.info("开始文本生成图像,request: {}", request);
|
||||
|
||||
try {
|
||||
// 调用服务层进行文本生成图像处理
|
||||
Map<String, Object> processingResponse = imageModelService.generateImageByText(request);
|
||||
|
||||
log.info("文本生成图像处理完成,生成图片数量: {}", processingResponse.get("imageCount"));
|
||||
|
||||
return ResponseEntity.ok(processingResponse);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("文本生成图像处理失败: {}", e.getMessage(), e);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "文本生成图像处理失败: " + e.getMessage());
|
||||
result.put("error", e.getClass().getSimpleName());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 图像处理接口,根据给的素材生成图片
|
||||
*/
|
||||
|
||||
@@ -137,6 +137,12 @@ public class TextModelController {
|
||||
@NotBlank(message = "图片名称")
|
||||
private String imageName;
|
||||
|
||||
@NotBlank(message = "提示词")
|
||||
private String prompt;
|
||||
|
||||
@NotBlank(message = "模型")
|
||||
private String model;
|
||||
|
||||
private ReferenceEdge referenceEdge;
|
||||
private Parameters parameters;
|
||||
}
|
||||
|
||||
@@ -395,6 +395,8 @@ public class MenuController {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -365,6 +365,8 @@ public class RoleController {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -371,6 +371,8 @@ public class UserRoleController {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -137,6 +137,8 @@ public class DifyWorkflowResponseDto {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ public interface CustomerProfileAnalysisMapper extends BaseMapper<CustomerProfil
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.rj.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.rj.controller.TextModelController;
|
||||
import com.rj.entity.ImageModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 图像模型服务接口
|
||||
*
|
||||
@@ -140,4 +143,17 @@ public interface IImageModelService extends IService<ImageModel> {
|
||||
String prompt, String functionName);
|
||||
|
||||
boolean removeByUuid(String uuid);
|
||||
|
||||
/**
|
||||
* 文本生成图像
|
||||
*
|
||||
* 根据文本提示词生成图像,包括:
|
||||
* - 调用AI图像生成服务
|
||||
* - 处理生成结果
|
||||
* - 保存生成记录
|
||||
*
|
||||
* @param request 文本生成图像请求参数
|
||||
* @return 生成结果,包含图像URL等信息
|
||||
*/
|
||||
Map<String, Object> generateImageByText(TextModelController.ImageProcessingRequest request);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ public interface ICustomerProfileAnalysisService extends IService<CustomerProfil
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +136,8 @@ public class CustomerProfileAnalysisServiceImpl extends ServiceImpl<CustomerProf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,10 +4,18 @@ 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;
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
|
||||
import com.alibaba.dashscope.common.MultiModalMessage;
|
||||
import com.alibaba.dashscope.common.Role;
|
||||
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.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.rj.controller.TextModelController;
|
||||
import com.rj.entity.ImageModel;
|
||||
import com.rj.mapper.ImageModelMapper;
|
||||
import com.rj.service.IImageModelService;
|
||||
@@ -20,9 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 图像模型服务实现类
|
||||
@@ -276,7 +282,8 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
} else {
|
||||
log.warn("AI处理结果为空或无效");
|
||||
}
|
||||
|
||||
|
||||
imageModel.setImageType("remove_water");
|
||||
// 6. 保存处理记录
|
||||
boolean saveResult = this.updateById(imageModel);
|
||||
if (!saveResult) {
|
||||
@@ -887,4 +894,195 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本生成图像
|
||||
*
|
||||
* 根据文本提示词生成图像,包括:
|
||||
* - 调用AI图像生成服务
|
||||
* - 处理生成结果
|
||||
* - 保存生成记录
|
||||
*
|
||||
* @param request 文本生成图像请求参数
|
||||
* @return 生成结果,包含图像URL等信息
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> generateImageByText(TextModelController.ImageProcessingRequest request) {
|
||||
try {
|
||||
log.info("开始文本生成图像,提示词: {},模型: {}", request.getPrompt(), request.getModel());
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
// 1. 参数验证
|
||||
if (request.getPrompt() == null || request.getPrompt().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("提示词不能为空");
|
||||
}
|
||||
|
||||
if (request.getModel() == null || request.getModel().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("模型名称不能为空");
|
||||
}
|
||||
|
||||
// 2. 调用阿里云图像生成API
|
||||
String apiKey = System.getenv("DASHSCOPE_API_KEY");
|
||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
||||
throw new RuntimeException("未配置DASHSCOPE_API_KEY环境变量");
|
||||
}
|
||||
|
||||
// 3. 设置API基础URL(参考测试类)
|
||||
Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
|
||||
|
||||
// 4. 构建多模态对话参数(参考测试类)
|
||||
MultiModalConversation conv = new MultiModalConversation();
|
||||
MultiModalMessage userMessage = MultiModalMessage.builder()
|
||||
.role(Role.USER.getValue())
|
||||
.content(Arrays.asList(
|
||||
Collections.singletonMap("text", request.getPrompt())
|
||||
)).build();
|
||||
|
||||
// 5. 构建参数(参考测试类)
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("watermark", true);
|
||||
parameters.put("prompt_extend", true);
|
||||
parameters.put("negative_prompt", "");
|
||||
parameters.put("size", "1328*1328"); // 使用阿里云允许的尺寸
|
||||
|
||||
MultiModalConversationParam param = MultiModalConversationParam.builder()
|
||||
.apiKey(apiKey)
|
||||
.model("qwen-image-plus") // 使用固定的模型名称
|
||||
.messages(Collections.singletonList(userMessage))
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
|
||||
// 6. 调用图像生成服务
|
||||
MultiModalConversationResult conversationResult = null;
|
||||
|
||||
try {
|
||||
log.info("开始调用阿里云多模态对话API,参数: {}", param);
|
||||
conversationResult = conv.call(param);
|
||||
log.info("多模态对话API调用完成,结果: {}", JsonUtils.toJson(conversationResult));
|
||||
|
||||
} catch (ApiException | NoApiKeyException | UploadFileException e) {
|
||||
log.error("阿里云多模态对话API调用失败", e);
|
||||
throw new RuntimeException("图像生成API调用失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 7. 处理生成结果
|
||||
if (conversationResult != null && conversationResult.getOutput() != null &&
|
||||
conversationResult.getOutput().getChoices() != null &&
|
||||
!conversationResult.getOutput().getChoices().isEmpty()) {
|
||||
|
||||
log.info("图像生成成功,开始处理结果");
|
||||
log.info("完整API返回结果: {}", JsonUtils.toJson(conversationResult));
|
||||
|
||||
// 从多模态对话结果中提取图像URL
|
||||
String generatedImageUrl = null;
|
||||
try {
|
||||
// 根据您提供的返回结果格式解析图像URL
|
||||
// 返回格式:{"output": {"choices": [{"message": {"content": [{"image": "url"}]}}]}}
|
||||
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()) {
|
||||
// content是一个List,包含多个内容项
|
||||
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,完整结果: {}", JsonUtils.toJson(conversationResult));
|
||||
throw new RuntimeException("未能从API返回结果中提取图像URL");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析API返回结果失败", e);
|
||||
throw new RuntimeException("解析API返回结果失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
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 = new ImageModel();
|
||||
imageModel.setImageName(request.getImageName() != null ? request.getImageName() : "文本生成图像");
|
||||
imageModel.setOwnerName(request.getOwnerName());
|
||||
imageModel.setOwnerPhone(request.getOwnerPhone());
|
||||
imageModel.setImageType("text_to_image");
|
||||
imageModel.setPrompt(request.getPrompt());
|
||||
imageModel.setModelName(request.getModel());
|
||||
imageModel.setResultImageUrl(resultImageMinIOUrl);
|
||||
imageModel.setResultImageTempUrl(resultImageTempUrl);
|
||||
imageModel.setCreateTime(LocalDateTime.now());
|
||||
imageModel.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 保存到数据库
|
||||
boolean saveResult = this.saveImageModel(imageModel);
|
||||
if (!saveResult) {
|
||||
log.error("保存文本生成图像记录失败");
|
||||
throw new RuntimeException("保存文本生成图像记录失败");
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
result.put("success", true);
|
||||
result.put("message", "文本生成图像处理完成");
|
||||
result.put("imageCount", 1);
|
||||
result.put("imageUrl", resultImageTempUrl);
|
||||
result.put("imageMinIOUrl", resultImageMinIOUrl);
|
||||
result.put("prompt", request.getPrompt());
|
||||
result.put("model", request.getModel());
|
||||
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 (Exception e) {
|
||||
log.error("文本生成图像异常", e);
|
||||
throw new RuntimeException("文本生成图像失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -108,6 +108,8 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IM
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IR
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ spring:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -94,6 +94,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -293,6 +293,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
67
src/test/java/com/rj/image/QwenImage.java
Normal file
67
src/test/java/com/rj/image/QwenImage.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package com.rj.image;
|
||||
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
|
||||
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
|
||||
import com.alibaba.dashscope.common.MultiModalMessage;
|
||||
import com.alibaba.dashscope.common.Role;
|
||||
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 java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QwenImage {
|
||||
|
||||
static {
|
||||
// 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:https://dashscope-intl.aliyuncs.com/api/v1
|
||||
Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
|
||||
}
|
||||
|
||||
// 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey="sk-xxx"
|
||||
// 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
|
||||
static String apiKey = System.getenv("DASHSCOPE_API_KEY");
|
||||
|
||||
public static void call() throws ApiException, NoApiKeyException, UploadFileException, IOException {
|
||||
|
||||
MultiModalConversation conv = new MultiModalConversation();
|
||||
String content1 = "一张在海滩上拍摄的照片。照片中是一位穿着浅色比基尼的女性,她站在海边,背景是海浪、沙滩和远处的山丘。天空晴朗,阳光明媚,整体环境显得非常自然和放松。微笑着,一只手抚摸头发,很妩媚,似乎在享受海边的时光。";
|
||||
String content = "一张在海滩上拍摄的照片。照片中是一位穿着浅色比基尼的女性,她站在海边,背景是海浪、沙滩和远处的山丘。天空晴朗,阳光明媚,整体环境显得非常自然和放松。这位女性面带微笑,双臂微微张开,似乎在享受海边的时光。";
|
||||
MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
|
||||
.content(Arrays.asList(
|
||||
// Collections.singletonMap("text", "一副典雅庄重的对联悬挂于厅堂之中,房间是个安静古典的中式布置,桌子上放着一些青花瓷,对联上左书“义本生知人机同道善思新”,右书“通云赋智乾坤启数高志远”, 横批“智启通义”,字体飘逸,中间挂在一着一副中国风的画作,内容是岳阳楼。")
|
||||
Collections.singletonMap("text", content)
|
||||
)).build();
|
||||
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("watermark", true);
|
||||
parameters.put("prompt_extend", true);
|
||||
parameters.put("negative_prompt", "");
|
||||
parameters.put("size", "1328*1328");
|
||||
|
||||
MultiModalConversationParam param = MultiModalConversationParam.builder()
|
||||
.apiKey(apiKey)
|
||||
.model("qwen-image-plus")
|
||||
.messages(Collections.singletonList(userMessage))
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
System.out.println("开始调用阿里云多模态对话API,参数 :"+ param);
|
||||
MultiModalConversationResult result = conv.call(param);
|
||||
System.out.println(JsonUtils.toJson(result));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
call();
|
||||
} catch (ApiException | NoApiKeyException | UploadFileException | IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -231,6 +231,8 @@ public class FaceDetectImageCountTest {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -172,6 +172,8 @@ public class TtsRequestLogShortUrlTest {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -150,6 +150,8 @@ public class VideoSynthesisTempUrlTest {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ public class VideoSynthesisVideoNameTest {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user