From bb71cf9458a90e486d9e6e6042cb1e65bf2ec39e Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 6 Dec 2025 16:11:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(image):=20=E6=96=B0=E5=A2=9EAI=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E7=85=A7=E7=89=87=E5=A2=9E=E5=BC=BA=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在PipelineScene枚举中新增AI_CAM_ENHANCE场景 - 修改setUserIsBuyItem方法,增加对AI相机照片的图像处理逻辑 - 新增processAiCamImages方法,批量处理AI相机照片 - 新增processSingleAiCamImage方法,处理单张AI相机照片 - 新增buildEnhancerConfig方法,构建图像增强配置 - 实现图像处理管线:下载->超分->增强->上传->清理 - 添加处理结果URL回调更新机制 - 增加异常处理和日志记录,确保处理失败不影响主流程 --- .../java/com/ycwl/basic/biz/OrderBiz.java | 2 +- .../image/pipeline/enums/PipelineScene.java | 8 +- .../basic/repository/SourceRepository.java | 133 ++++++++++++++++++ 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ycwl/basic/biz/OrderBiz.java b/src/main/java/com/ycwl/basic/biz/OrderBiz.java index f1731a34..fc0dac5b 100644 --- a/src/main/java/com/ycwl/basic/biz/OrderBiz.java +++ b/src/main/java/com/ycwl/basic/biz/OrderBiz.java @@ -220,7 +220,7 @@ public class OrderBiz { break; case 1: // 视频原素材 case 2: // 照片原素材 - case 13: // AI微单 + case 13: // AI微单 sourceRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId(), order.getId()); break; case 3: diff --git a/src/main/java/com/ycwl/basic/image/pipeline/enums/PipelineScene.java b/src/main/java/com/ycwl/basic/image/pipeline/enums/PipelineScene.java index 14a3ac1b..5837f6b2 100644 --- a/src/main/java/com/ycwl/basic/image/pipeline/enums/PipelineScene.java +++ b/src/main/java/com/ycwl/basic/image/pipeline/enums/PipelineScene.java @@ -22,7 +22,13 @@ public enum PipelineScene { * 源图片超分辨率增强场景 * IPC设备拍摄的源图片进行质量提升 */ - SOURCE_PHOTO_SUPER_RESOLUTION("source_photo_sr", "源图片超分辨率增强"); + SOURCE_PHOTO_SUPER_RESOLUTION("source_photo_sr", "源图片超分辨率增强"), + + /** + * AI相机照片增强场景 + * AI相机拍摄的照片进行超分辨率和质量增强 + */ + AI_CAM_ENHANCE("ai_cam_enhance", "AI相机照片增强"); private final String code; private final String description; diff --git a/src/main/java/com/ycwl/basic/repository/SourceRepository.java b/src/main/java/com/ycwl/basic/repository/SourceRepository.java index c070c1ce..96685e1e 100644 --- a/src/main/java/com/ycwl/basic/repository/SourceRepository.java +++ b/src/main/java/com/ycwl/basic/repository/SourceRepository.java @@ -1,10 +1,18 @@ package com.ycwl.basic.repository; +import com.ycwl.basic.image.enhancer.entity.BceEnhancerConfig; +import com.ycwl.basic.image.pipeline.core.PhotoProcessContext; +import com.ycwl.basic.image.pipeline.enums.ImageSource; +import com.ycwl.basic.image.pipeline.enums.ImageType; +import com.ycwl.basic.image.pipeline.enums.PipelineScene; +import com.ycwl.basic.image.pipeline.stages.*; import com.ycwl.basic.mapper.SourceMapper; import com.ycwl.basic.model.pc.face.entity.FaceEntity; import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity; import com.ycwl.basic.model.pc.source.entity.SourceEntity; import com.ycwl.basic.model.pc.device.entity.DeviceEntity; +import com.ycwl.basic.pipeline.core.Pipeline; +import com.ycwl.basic.pipeline.core.PipelineBuilder; import com.ycwl.basic.pricing.dto.VoucherInfo; import com.ycwl.basic.pricing.enums.VoucherDiscountType; import com.ycwl.basic.pricing.service.IVoucherService; @@ -41,9 +49,18 @@ public class SourceRepository { } public void setUserIsBuyItem(Long memberId, int type, Long faceId, Long orderId) { + // 如果是AI相机照片类型(type=13),需要进行图像超分和增强处理 + boolean needsImageProcessing = (type == 13 || type == 3); + if (type == 13) { type = 3; // compact } + + // 如果需要图像处理,对该faceId下的所有type=3的照片进行处理 + if (needsImageProcessing) { + processAiCamImages(faceId); + } + MemberSourceEntity memberSource = new MemberSourceEntity(); memberSource.setMemberId(memberId); memberSource.setFaceId(faceId); @@ -54,6 +71,122 @@ public class SourceRepository { memberRelationRepository.clearSCacheByFace(faceId); } + /** + * 处理AI相机照片 - 对照片进行超分辨率和增强处理 + * + * @param faceId 人脸ID + */ + private void processAiCamImages(Long faceId) { + try { + // 1. 获取该faceId下所有type=3的照片 + List aiCamImages = sourceMapper.listAiCamImageByFaceRelation(faceId); + + if (aiCamImages == null || aiCamImages.isEmpty()) { + log.info("没有找到需要处理的AI相机照片, faceId: {}", faceId); + return; + } + + log.info("开始处理AI相机照片, faceId: {}, 照片数量: {}", faceId, aiCamImages.size()); + + // 2. 构建图像处理配置 + BceEnhancerConfig config = buildEnhancerConfig(); + + // 3. 为每张照片创建处理管线并执行 + for (SourceEntity source : aiCamImages) { + try { + processSingleAiCamImage(source, config); + } catch (Exception e) { + log.error("处理AI相机照片失败, sourceId: {}, error: {}", source.getId(), e.getMessage(), e); + // 继续处理下一张照片,不中断整个流程 + } + } + + log.info("AI相机照片处理完成, faceId: {}", faceId); + + } catch (Exception e) { + log.error("处理AI相机照片整体流程失败, faceId: {}, error: {}", faceId, e.getMessage(), e); + // 即使处理失败也不抛出异常,不影响订单购买流程 + } + } + + /** + * 处理单张AI相机照片 + * + * @param source 原始照片 + * @param config 增强配置 + */ + private void processSingleAiCamImage(SourceEntity source, BceEnhancerConfig config) { + // 1. 创建处理上下文 + PhotoProcessContext context = PhotoProcessContext.builder() + .processId("aicam-" + source.getId()) + .originalUrl(source.getUrl()) + .scenicId(source.getScenicId()) + .imageType(ImageType.NORMAL_PHOTO) + .source(ImageSource.IPC) + .scene(PipelineScene.AI_CAM_ENHANCE) + .build(); + context.enableStage("image_sr"); + context.enableStage("image_enhance"); + + // 2. 设置结果URL回调 - 更新source记录 + context.setResultUrlCallback(newUrl -> { + SourceEntity updateEntity = new SourceEntity(); + updateEntity.setId(source.getId()); + updateEntity.setUrl(newUrl); + sourceMapper.update(updateEntity); + log.info("已更新AI相机照片URL, sourceId: {}, oldUrl: {}, newUrl: {}", + source.getId(), source.getUrl(), newUrl); + }); + + // 3. 构建处理管线: 下载 -> 超分 -> 增强 -> 上传 -> 清理 + Pipeline pipeline = new PipelineBuilder("AiCamEnhancePipeline") + .addStage(new DownloadStage()) // 下载原图 + .addStage(new ImageSRStage(config)) // 图像超分辨率 + .addStage(new ImageEnhanceStage(config)) // 图像增强 + .addStage(new UploadStage()) // 上传处理后的图片 + .addStage(new CleanupStage()) // 清理临时文件 + .build(); + + // 4. 执行管线 + boolean success = pipeline.execute(context); + + if (!success) { + log.warn("AI相机照片处理管线执行失败, sourceId: {}", source.getId()); + } + } + + /** + * 构建图像增强配置 + * + * @return 增强配置 + */ + private BceEnhancerConfig buildEnhancerConfig() { + BceEnhancerConfig config = new BceEnhancerConfig(); + + // 尝试从环境变量读取 + String appId = System.getenv("BCE_IMAGE_APP_ID"); + String apiKey = System.getenv("BCE_IMAGE_API_KEY"); + String secretKey = System.getenv("BCE_IMAGE_SECRET_KEY"); + + // 如果环境变量没有配置,使用默认值(与PrinterServiceImpl保持一致) + if (appId == null || appId.isBlank()) { + appId = "119554288"; + } + if (apiKey == null || apiKey.isBlank()) { + apiKey = "OX6QoijgKio3eVtA0PiUVf7f"; + } + if (secretKey == null || secretKey.isBlank()) { + secretKey = "dYatXReVriPeiktTjUblhfubpcmYfuMk"; + } + + config.setAppId(appId); + config.setApiKey(apiKey); + config.setSecretKey(secretKey); + config.setQps(1.0f); + + return config; + } + public void setUserNotBuyItem(Long memberId, int type, Long faceId) { MemberSourceEntity memberSource = new MemberSourceEntity(); memberSource.setMemberId(memberId);