From 9b2e08593c3ad293737f68fe1d2057f87f3819a2 Mon Sep 17 00:00:00 2001 From: spllzh <28668817@qq.com> Date: Sat, 18 Oct 2025 10:48:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=9C=AC=E7=94=9F=E6=88=90=E5=9B=BE?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rj/common/PasswordUtil.java | 2 + .../java/com/rj/common/ServiceManager.java | 2 + src/main/java/com/rj/config/AliyunConfig.java | 2 + .../rj/controller/ImageModelController.java | 25 +++ .../rj/controller/TextModelController.java | 6 + .../com/rj/controller/sys/MenuController.java | 2 + .../com/rj/controller/sys/RoleController.java | 2 + .../rj/controller/sys/UserRoleController.java | 2 + .../com/rj/dto/DifyWorkflowResponseDto.java | 2 + .../mapper/CustomerProfileAnalysisMapper.java | 2 + .../com/rj/service/IImageModelService.java | 16 ++ .../biz/ICustomerProfileAnalysisService.java | 2 + .../CustomerProfileAnalysisServiceImpl.java | 2 + .../service/impl/ImageModelServiceImpl.java | 206 +++++++++++++++++- .../rj/service/sys/impl/MenuServiceImpl.java | 2 + .../rj/service/sys/impl/RoleServiceImpl.java | 2 + .../service/sys/impl/UserRoleServiceImpl.java | 2 + src/main/resources/application-audio.yml | 2 + .../AudioManagementStatisticsMapper.xml | 2 + src/main/resources/static/tts-demo.html | 2 + src/test/java/com/rj/image/QwenImage.java | 67 ++++++ .../rj/service/FaceDetectImageCountTest.java | 2 + .../rj/service/TtsRequestLogShortUrlTest.java | 2 + .../rj/service/VideoSynthesisTempUrlTest.java | 2 + .../service/VideoSynthesisVideoNameTest.java | 2 + 25 files changed, 356 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/rj/image/QwenImage.java diff --git a/src/main/java/com/rj/common/PasswordUtil.java b/src/main/java/com/rj/common/PasswordUtil.java index 1ff5d95..aae39b4 100644 --- a/src/main/java/com/rj/common/PasswordUtil.java +++ b/src/main/java/com/rj/common/PasswordUtil.java @@ -173,6 +173,8 @@ public class PasswordUtil { + + diff --git a/src/main/java/com/rj/common/ServiceManager.java b/src/main/java/com/rj/common/ServiceManager.java index e6776c7..e88cb5e 100644 --- a/src/main/java/com/rj/common/ServiceManager.java +++ b/src/main/java/com/rj/common/ServiceManager.java @@ -157,6 +157,8 @@ public class ServiceManager { + + diff --git a/src/main/java/com/rj/config/AliyunConfig.java b/src/main/java/com/rj/config/AliyunConfig.java index 259cc85..0a96bbe 100644 --- a/src/main/java/com/rj/config/AliyunConfig.java +++ b/src/main/java/com/rj/config/AliyunConfig.java @@ -134,6 +134,8 @@ public class AliyunConfig { + + diff --git a/src/main/java/com/rj/controller/ImageModelController.java b/src/main/java/com/rj/controller/ImageModelController.java index 1a0bc9b..8a22649 100644 --- a/src/main/java/com/rj/controller/ImageModelController.java +++ b/src/main/java/com/rj/controller/ImageModelController.java @@ -678,6 +678,31 @@ public class ImageModelController { } } + @PostMapping("/image-gen-byText") + @Operation(summary = "文本生成图像", description = "基于文本提示词生成图像") + public ResponseEntity> imageGen( + @Parameter(description = "文本生成图像") @Valid @RequestBody TextModelController.ImageProcessingRequest request) { + log.info("开始文本生成图像,request: {}", request); + + try { + // 调用服务层进行文本生成图像处理 + Map processingResponse = imageModelService.generateImageByText(request); + + log.info("文本生成图像处理完成,生成图片数量: {}", processingResponse.get("imageCount")); + + return ResponseEntity.ok(processingResponse); + + } catch (Exception e) { + log.error("文本生成图像处理失败: {}", e.getMessage(), e); + Map 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); + } + } + + /** * 图像处理接口,根据给的素材生成图片 */ diff --git a/src/main/java/com/rj/controller/TextModelController.java b/src/main/java/com/rj/controller/TextModelController.java index 81498df..d60257e 100644 --- a/src/main/java/com/rj/controller/TextModelController.java +++ b/src/main/java/com/rj/controller/TextModelController.java @@ -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; } diff --git a/src/main/java/com/rj/controller/sys/MenuController.java b/src/main/java/com/rj/controller/sys/MenuController.java index b296441..ed3ca43 100644 --- a/src/main/java/com/rj/controller/sys/MenuController.java +++ b/src/main/java/com/rj/controller/sys/MenuController.java @@ -395,6 +395,8 @@ public class MenuController { + + diff --git a/src/main/java/com/rj/controller/sys/RoleController.java b/src/main/java/com/rj/controller/sys/RoleController.java index 1714499..baa9b36 100644 --- a/src/main/java/com/rj/controller/sys/RoleController.java +++ b/src/main/java/com/rj/controller/sys/RoleController.java @@ -365,6 +365,8 @@ public class RoleController { + + diff --git a/src/main/java/com/rj/controller/sys/UserRoleController.java b/src/main/java/com/rj/controller/sys/UserRoleController.java index 9612540..bf76a4b 100644 --- a/src/main/java/com/rj/controller/sys/UserRoleController.java +++ b/src/main/java/com/rj/controller/sys/UserRoleController.java @@ -371,6 +371,8 @@ public class UserRoleController { + + diff --git a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java index 7451cfd..21f0fa7 100644 --- a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java +++ b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java @@ -137,6 +137,8 @@ public class DifyWorkflowResponseDto { + + diff --git a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java index 7ac9b18..0530ac2 100644 --- a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java +++ b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java @@ -80,6 +80,8 @@ public interface CustomerProfileAnalysisMapper extends BaseMapper { String prompt, String functionName); boolean removeByUuid(String uuid); + + /** + * 文本生成图像 + * + * 根据文本提示词生成图像,包括: + * - 调用AI图像生成服务 + * - 处理生成结果 + * - 保存生成记录 + * + * @param request 文本生成图像请求参数 + * @return 生成结果,包含图像URL等信息 + */ + Map generateImageByText(TextModelController.ImageProcessingRequest request); } diff --git a/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java b/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java index 1d60009..2dab9fc 100644 --- a/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java +++ b/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java @@ -101,6 +101,8 @@ public interface ICustomerProfileAnalysisService extends IService generateImageByText(TextModelController.ImageProcessingRequest request) { + try { + log.info("开始文本生成图像,提示词: {},模型: {}", request.getPrompt(), request.getModel()); + + Map 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 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 contentMap = (Map) 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); + } + } + } diff --git a/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java b/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java index d2fcb83..280e38c 100644 --- a/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java @@ -108,6 +108,8 @@ public class MenuServiceImpl extends ServiceImpl implements IM + + diff --git a/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java b/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java index 96d1987..48e858c 100644 --- a/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java @@ -108,6 +108,8 @@ public class RoleServiceImpl extends ServiceImpl implements IR + + diff --git a/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java b/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java index d19e8b4..0917a5a 100644 --- a/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java @@ -108,6 +108,8 @@ public class UserRoleServiceImpl extends ServiceImpl i + + diff --git a/src/main/resources/application-audio.yml b/src/main/resources/application-audio.yml index 023cb4e..ebd2309 100644 --- a/src/main/resources/application-audio.yml +++ b/src/main/resources/application-audio.yml @@ -117,6 +117,8 @@ spring: + + diff --git a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml index 8e30eaf..dce7c6a 100644 --- a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml +++ b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml @@ -94,6 +94,8 @@ + + diff --git a/src/main/resources/static/tts-demo.html b/src/main/resources/static/tts-demo.html index 21a047d..6a67a93 100644 --- a/src/main/resources/static/tts-demo.html +++ b/src/main/resources/static/tts-demo.html @@ -293,6 +293,8 @@ + + diff --git a/src/test/java/com/rj/image/QwenImage.java b/src/test/java/com/rj/image/QwenImage.java new file mode 100644 index 0000000..2712632 --- /dev/null +++ b/src/test/java/com/rj/image/QwenImage.java @@ -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 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); + } +} \ No newline at end of file diff --git a/src/test/java/com/rj/service/FaceDetectImageCountTest.java b/src/test/java/com/rj/service/FaceDetectImageCountTest.java index f3e4175..1a386f8 100644 --- a/src/test/java/com/rj/service/FaceDetectImageCountTest.java +++ b/src/test/java/com/rj/service/FaceDetectImageCountTest.java @@ -231,6 +231,8 @@ public class FaceDetectImageCountTest { + + diff --git a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java index f9484e2..d8c1a89 100644 --- a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java +++ b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java @@ -172,6 +172,8 @@ public class TtsRequestLogShortUrlTest { + + diff --git a/src/test/java/com/rj/service/VideoSynthesisTempUrlTest.java b/src/test/java/com/rj/service/VideoSynthesisTempUrlTest.java index 6b2afad..9c2efc2 100644 --- a/src/test/java/com/rj/service/VideoSynthesisTempUrlTest.java +++ b/src/test/java/com/rj/service/VideoSynthesisTempUrlTest.java @@ -150,6 +150,8 @@ public class VideoSynthesisTempUrlTest { + + diff --git a/src/test/java/com/rj/service/VideoSynthesisVideoNameTest.java b/src/test/java/com/rj/service/VideoSynthesisVideoNameTest.java index debacce..640cce3 100644 --- a/src/test/java/com/rj/service/VideoSynthesisVideoNameTest.java +++ b/src/test/java/com/rj/service/VideoSynthesisVideoNameTest.java @@ -125,6 +125,8 @@ public class VideoSynthesisVideoNameTest { + +