图像模型

This commit is contained in:
spllzh
2025-10-15 09:22:08 +08:00
parent 71c0a04b53
commit abd370beb5
23 changed files with 1613 additions and 22 deletions

View File

@@ -0,0 +1,111 @@
package com.rj.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.rj.entity.ImageModel;
/**
* 图像模型服务接口
*
* 提供图像模型相关的业务逻辑接口,包括:
* - 图像模型记录的增删改查操作
* - 根据不同条件查询图像模型记录
* - 图像模型数据的业务处理逻辑
*
* 继承MyBatis-Plus的IService接口获得基础的CRUD能力
* 同时定义特定的业务方法。
*
* @author 系统生成
* @date 2025/1/30
* @version 1.0
*/
public interface IImageModelService extends IService<ImageModel> {
/**
* 保存图像模型记录
*
* 将图像模型数据保存到数据库中,包括完整的业务逻辑处理。
* 该方法会进行数据验证、日志记录等操作。
*
* @param imageModel 图像模型记录对象,包含所有必要的字段信息
* @return 是否保存成功true表示保存成功false表示保存失败
*/
boolean saveImageModel(ImageModel imageModel);
/**
* 根据UUID查询图像模型记录
*
* 通过唯一标识符查询对应的图像模型记录。
* UUID是主键查询结果唯一。
*
* @param uuid 唯一标识符,对应数据库主键
* @return 图像模型记录如果未找到则返回null
*/
ImageModel getByUuid(String uuid);
/**
* 根据请求ID查询图像模型记录
*
* 通过请求ID查询对应的图像模型记录。
* 一个请求ID可能对应多条记录此方法返回最新的一条。
*
* @param requestId 请求ID用于追踪处理请求
* @return 图像模型记录如果未找到则返回null
*/
ImageModel getByRequestId(String requestId);
/**
* 根据任务ID查询图像模型记录
*
* 通过任务ID查询对应的图像模型记录。
* 一个任务ID可能对应多条记录此方法返回最新的一条。
*
* @param taskId 任务ID用于追踪异步处理任务
* @return 图像模型记录如果未找到则返回null
*/
ImageModel getByTaskId(String taskId);
/**
* 根据所属人电话查询图像模型记录
*
* 通过所属人电话查询对应的图像模型记录。
* 一个电话号码可能对应多条记录,此方法返回最新的一条。
*
* @param ownerPhone 所属人电话,用于查询特定用户的记录
* @return 图像模型记录如果未找到则返回null
*/
ImageModel getByOwnerPhone(String ownerPhone);
/**
* 去除图像中的中英文字符或常见水印
*
* 处理图像去除水印的业务逻辑,包括:
* - 图像预处理和参数设置
* - 调用AI模型进行水印去除
* - 结果处理和URL生成
* - 记录保存和状态更新
*
* @param imageModel 图像模型记录对象,包含处理参数和结果信息
* @return 处理后的图像模型记录包含结果URL等信息
*/
ImageModel removeWatermar(ImageModel imageModel);
/**
* 上传图片素材
*
* 处理图片素材上传的完整业务逻辑,包括:
* - 文件验证和格式检查
* - 上传到MinIO存储
* - 生成永久URL和临时URL
* - 保存上传记录到数据库
*
* @param file 上传的图片文件
* @param ownerName 所属人姓名
* @param ownerPhone 所属人电话
* @param imageType 图片类型
* @return 图像模型记录包含上传结果和URL信息
*/
ImageModel uploadImageMaterial(org.springframework.web.multipart.MultipartFile file,
String ownerName, String ownerPhone, String imageType,String imageName);
boolean removeByUuid(String uuid);
}

View File

@@ -84,6 +84,11 @@ public interface ICustomerProfileAnalysisService extends IService<CustomerProfil

View File

@@ -119,6 +119,11 @@ public class CustomerProfileAnalysisServiceImpl extends ServiceImpl<CustomerProf

View File

@@ -0,0 +1,476 @@
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;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.ImageModel;
import com.rj.mapper.ImageModelMapper;
import com.rj.service.IImageModelService;
import com.rj.service.MinIOService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
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;
/**
* 图像模型服务实现类
*
* 实现IImageModelService接口中定义的所有业务方法。
* 该类负责处理图像模型相关的业务逻辑,包括:
* - 图像模型记录的保存、查询、更新、删除操作
* - 根据各种条件查询图像模型记录
* - 异常处理和日志记录
*
* 继承ServiceImpl获得MyBatis-Plus提供的基础CRUD能力
* 同时实现自定义的业务方法。
*
* @author 系统生成
* @date 2025/1/30
* @version 1.0
*/
@Slf4j
@Service
public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageModel>
implements IImageModelService {
@Autowired
private MinIOService minIOService;
/**
* 保存图像模型记录
*
* 将图像模型数据保存到数据库中,包含完整的异常处理和日志记录。
* 该方法会记录操作开始、成功或失败的日志信息。
*
* @param imageModel 图像模型记录对象,包含所有必要的字段信息
* @return 是否保存成功true表示保存成功false表示保存失败
*/
@Override
public boolean saveImageModel(ImageModel imageModel) {
try {
log.info("保存图像模型记录开始,参数:{}", imageModel);
boolean result = this.save(imageModel);
if (result) {
log.info("图像模型记录保存成功ID: {}", imageModel.getUuid());
} else {
log.error("图像模型记录保存失败");
}
return result;
} catch (Exception e) {
log.error("保存图像模型记录异常", e);
return false;
}
}
/**
* 根据UUID查询图像模型记录
*
* 通过唯一标识符查询对应的图像模型记录。
* 使用LambdaQueryWrapper构建查询条件确保类型安全。
*
* @param uuid 唯一标识符,对应数据库主键
* @return 图像模型记录如果未找到则返回null
*/
@Override
public ImageModel getByUuid(String uuid) {
try {
LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImageModel::getUuid, uuid);
return this.getOne(queryWrapper);
} catch (Exception e) {
log.error("根据ID查询图像模型记录异常", e);
return null;
}
}
/**
* 根据请求ID查询图像模型记录
*
* 通过请求ID查询对应的图像模型记录。
* 由于一个请求ID可能对应多条记录此方法返回最新的一条。
* 查询结果按创建时间降序排列,取第一条记录。
*
* @param requestId 请求ID用于追踪处理请求
* @return 图像模型记录如果未找到则返回null
*/
@Override
public ImageModel getByRequestId(String requestId) {
try {
LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImageModel::getRequestId, requestId)
.orderByDesc(ImageModel::getCreateTime)
.last("LIMIT 1");
return this.getOne(queryWrapper);
} catch (Exception e) {
log.error("根据请求ID查询图像模型记录异常", e);
return null;
}
}
/**
* 根据任务ID查询图像模型记录
*
* 通过任务ID查询对应的图像模型记录。
* 由于一个任务ID可能对应多条记录此方法返回最新的一条。
* 查询结果按创建时间降序排列,取第一条记录。
*
* @param taskId 任务ID用于追踪异步处理任务
* @return 图像模型记录如果未找到则返回null
*/
@Override
public ImageModel getByTaskId(String taskId) {
try {
LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImageModel::getTaskId, taskId)
.orderByDesc(ImageModel::getCreateTime)
.last("LIMIT 1");
return this.getOne(queryWrapper);
} catch (Exception e) {
log.error("根据任务ID查询图像模型记录异常", e);
return null;
}
}
/**
* 根据所属人电话查询图像模型记录
*
* 通过所属人电话查询对应的图像模型记录。
* 由于一个电话号码可能对应多条记录,此方法返回最新的一条。
* 查询结果按创建时间降序排列,取第一条记录。
*
* @param ownerPhone 所属人电话,用于查询特定用户的记录
* @return 图像模型记录如果未找到则返回null
*/
@Override
public ImageModel getByOwnerPhone(String ownerPhone) {
try {
LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImageModel::getOwnerPhone, ownerPhone)
.orderByDesc(ImageModel::getCreateTime)
.last("LIMIT 1");
return this.getOne(queryWrapper);
} catch (Exception e) {
log.error("根据所属人电话查询图像模型记录异常", e);
return null;
}
}
/**
* 去除图像中的中英文字符或常见水印
*
* 实现图像水印去除的核心业务逻辑,包括:
* 1. 参数验证和预处理
* 2. 调用AI模型进行水印检测和去除
* 3. 处理结果并生成访问URL
* 4. 保存处理记录到数据库
* 5. 返回处理结果
*
* @param imageModel 图像模型记录对象,包含处理参数和结果信息
* @return 处理后的图像模型记录包含结果URL等信息
*/
@Override
public ImageModel removeWatermar(ImageModel imageModel) {
try {
log.info("开始去除图像水印,参数:{}", imageModel);
// 1. 参数验证
if (imageModel.getMaterialTempUrl() == null || imageModel.getMaterialTempUrl().trim().isEmpty()) {
log.error("素材URL不能为空");
throw new IllegalArgumentException("素材URL不能为空");
}
imageModel.setPrompt("去除图像中的文字");
imageModel.setModelName("wanx2.1-imageedit");
imageModel.setFunctionName("remove_watermark");
// 3. 模拟AI模型处理实际项目中这里会调用真实的AI服务
log.info("调用AI模型进行水印去除处理...");
/**
* {
* "input": {
* "function": "remove_watermark",
* "prompt": "去除图像中的文字",
* "base_image_url": "http://wanx.alicdn.com/material/20250318/remove_watermark_1.png"
* }
* }
*/
// 若没有配置环境变量请用百炼API Key将下行替换为apiKey="sk-xxx"
String apiKey = System.getenv("DASHSCOPE_API_KEY");
Map<String, Object> parameters = new HashMap<>();
parameters.put("prompt_extend", true);
ImageSynthesisParam param =
ImageSynthesisParam.builder()
.apiKey(apiKey)
.model(imageModel.getModelName())
.function(imageModel.getFunctionName())
.prompt(imageModel.getPrompt())
.baseImageUrl(imageModel.getMaterialTempUrl().trim())
.n(1)
.size("1024*1024")
.parameters(parameters)
.build();
ImageSynthesis imageSynthesis = new ImageSynthesis();
ImageSynthesisResult result = null;
try {
System.out.println("---sync call, please wait a moment----");
log.info("开始同步调用,参数是:{} ",param);
result = imageSynthesis.call(param);
log.info("返回结果 ", result);
System.out.println(JsonUtils.toJson(result));
result.getOutput().getResults().forEach(resultItem -> {
imageModel.setResultImageUrl(resultItem.get("url"));
});
} catch (ApiException | NoApiKeyException e){
log.error("api call error", e);
}
System.out.println(JsonUtils.toJson(result));
// 4. 下载AI处理结果图片并上传到MinIO
if (result != null && result.getOutput() != null && !result.getOutput().getResults().isEmpty()) {
String resultImageUrl = result.getOutput().getResults().get(0).get("url");
if (resultImageUrl != null && !resultImageUrl.trim().isEmpty()) {
log.info("开始下载AI处理结果图片: {}", resultImageUrl);
try {
// 下载图片到字节数组
byte[] imageBytes = downloadImageToBytes(resultImageUrl);
log.info("图片下载成功,大小: {} bytes", imageBytes.length);
// 生成唯一文件名
String resultFileName = generateUniqueFileName("jpg");
// 上传到MinIO
String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/jpeg");
log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
// 生成7天临时访问链接
String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
log.info("生成7天临时访问链接: {}", resultImageTempUrl);
// 更新ImageModel对象
imageModel.setResultImageUrl(resultImageMinIOUrl);
imageModel.setResultImageTempUrl(resultImageTempUrl);
} catch (Exception e) {
log.error("下载或上传AI处理结果图片失败", e);
throw new RuntimeException("处理结果图片失败: " + e.getMessage(), e);
}
} else {
log.warn("AI处理结果中没有有效的图片URL");
}
} else {
log.warn("AI处理结果为空或无效");
}
// 6. 保存处理记录
boolean saveResult = this.updateById(imageModel);
if (!saveResult) {
log.error("保存水印去除记录失败");
throw new RuntimeException("保存水印去除记录失败");
}
log.info("水印去除处理完成ID: {}, 结果URL: {}",
imageModel.getUuid(), imageModel.getResultImageTempUrl());
return imageModel;
} catch (Exception e) {
log.error("去除图像水印异常", e);
throw new RuntimeException("去除图像水印失败: " + e.getMessage(), e);
}
}
/**
* 上传图片素材
*
* 实现图片素材上传的完整业务逻辑,包括:
* 1. 文件验证和格式检查
* 2. 上传到MinIO存储
* 3. 生成永久URL和临时URL
* 4. 保存上传记录到数据库
*
* @param file 上传的图片文件
* @param ownerName 所属人姓名
* @param ownerPhone 所属人电话
* @param imageType 图片类型
* @return 图像模型记录包含上传结果和URL信息
*/
@Override
public ImageModel uploadImageMaterial(MultipartFile file, String ownerName, String ownerPhone, String imageType,String imageName) {
try {
log.info("开始上传图片素材,文件名:{},所属人:{},电话:{}",
file.getOriginalFilename(), ownerName, ownerPhone);
// 1. 文件验证
validateImageFile(file);
// 2. 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String fileExtension = getFileExtension(originalFilename);
String uniqueFileName = generateUniqueFileName(fileExtension);
// 3. 上传到MinIO
log.info("开始上传文件到MinIO文件名{}", uniqueFileName);
String materialUrl = minIOService.uploadFileWithName(file, uniqueFileName);
String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
// 4. 构建图像模型记录
ImageModel imageModel = new ImageModel();
imageModel.setImageName(originalFilename);
imageModel.setOwnerName(ownerName);
imageModel.setOwnerPhone(ownerPhone);
imageModel.setImageType(imageType);
imageModel.setMaterialUrl(materialUrl);
imageModel.setMaterialTempUrl(materialTempUrl);
imageModel.setCreateTime(LocalDateTime.now());
imageModel.setUpdateTime(LocalDateTime.now());
if ( imageName!=null && !imageName.trim().isEmpty()){
imageModel.setImageName(imageName);
}
// 5. 保存到数据库
boolean saveResult = this.saveImageModel(imageModel);
if (!saveResult) {
log.error("保存图片素材上传记录失败");
throw new RuntimeException("保存图片素材上传记录失败");
}
log.info("图片素材上传成功ID: {}永久URL: {}临时URL: {}",
imageModel.getUuid(), materialUrl, materialTempUrl);
return imageModel;
} catch (Exception e) {
log.error("上传图片素材异常", e);
throw new RuntimeException("上传图片素材失败: " + e.getMessage(), e);
}
}
@Override
public boolean removeByUuid(String uuid) {
boolean b = this.removeById(uuid);
return b;
}
/**
* 验证图片文件
*
* 检查文件格式、大小等是否符合要求
*
* @param file 上传的文件
* @throws IllegalArgumentException 文件不符合要求时抛出异常
*/
private void validateImageFile(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("上传文件不能为空");
}
// 检查文件大小限制为10MB
long maxSize = 10 * 1024 * 1024; // 10MB
if (file.getSize() > maxSize) {
throw new IllegalArgumentException("文件大小不能超过10MB");
}
// 检查文件格式
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
throw new IllegalArgumentException("只能上传图片文件");
}
// 检查文件扩展名
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.trim().isEmpty()) {
throw new IllegalArgumentException("文件名不能为空");
}
String extension = getFileExtension(originalFilename).toLowerCase();
String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
boolean isValidExtension = false;
for (String allowedExt : allowedExtensions) {
if (extension.equals(allowedExt)) {
isValidExtension = true;
break;
}
}
if (!isValidExtension) {
throw new IllegalArgumentException("不支持的图片格式支持的格式jpg, jpeg, png, gif, bmp, webp");
}
}
/**
* 获取文件扩展名
*
* @param filename 文件名
* @return 文件扩展名
*/
private String getFileExtension(String filename) {
if (filename == null || filename.lastIndexOf('.') == -1) {
return "";
}
return filename.substring(filename.lastIndexOf('.') + 1);
}
/**
* 生成唯一文件名
*
* 格式时间戳_UUID.扩展名
*
* @param extension 文件扩展名
* @return 唯一文件名
*/
private String generateUniqueFileName(String extension) {
long timestamp = System.currentTimeMillis();
String uuid = UUID.randomUUID().toString().replace("-", "");
return timestamp + "_" + uuid + "." + extension;
}
/**
* 下载图片到字节数组
*
* 从指定URL下载图片并返回字节数组
*
* @param imageUrl 图片URL
* @return 图片字节数组
* @throws IOException 下载失败时抛出异常
*/
private byte[] downloadImageToBytes(String imageUrl) throws IOException {
try {
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);
}
byte[] imageBytes = outputStream.toByteArray();
log.info("图片下载完成,大小: {} bytes", imageBytes.length);
return imageBytes;
}
} catch (Exception e) {
log.error("下载图片失败: {}", imageUrl, e);
throw new IOException("下载图片失败: " + e.getMessage(), e);
}
}
}

View File

@@ -91,6 +91,11 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IM

View File

@@ -91,6 +91,11 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IR

View File

@@ -91,6 +91,11 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i