Browse Source

feat(api): 添加场景图参考图功能支持

- 在API参数中新增product_scene_image字段用于传递场景图参考图
- 修改场景图生成流程,将参考图参数传递给AIGC处理函数
- 更新模型定义,为product_scene_image添加默认值和描述
- 重构场景图处理相关函数签名,统一添加参考图参数
- 修改generateProductScene方法,集成参考图到生成请求中
- 优化代码格式和空格规范,提升代码可读性
- 移除不必要的异步事件循环创建,优化资源管理
rambo 1 month ago
parent
commit
0586d6473b
3 changed files with 37 additions and 28 deletions
  1. 10 6
      python/api.py
  2. 4 1
      python/models.py
  3. 23 21
      python/service/online_request/module_online_data.py

+ 10 - 6
python/api.py

@@ -288,6 +288,7 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
         is_upper_footer = params.is_upper_footer
         upper_footer_params = params.upper_footer_params
         product_scene_prompt = params.product_scene_prompt
+        product_scene_image = params.product_scene_image
 
         if params.excel_path and params.excel_path.strip():
             # 处理Excel模式
@@ -349,7 +350,7 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
         # 处理场景图
         if is_product_scene == 1:
             return_data_check_before_detail = await _process_scene_images(
-                aigc_clazz, run_main, return_data_check_before_detail, product_scene_prompt
+                aigc_clazz, run_main, return_data_check_before_detail, product_scene_prompt, product_scene_image
             )
 
         # 处理模特图
@@ -624,7 +625,8 @@ async def _process_cutout(run_main, config_data, goods_art_no_arrays, move_folde
     return handler_result_folder, handler_result
 
 
-async def _process_single_scene_item(aigc_clazz, goods_art_dict_info_item, product_scene_prompt, save_root_path):
+async def _process_single_scene_item(aigc_clazz, goods_art_dict_info_item, product_scene_prompt, save_root_path,
+                                     product_scene_image):
     """将单个货号的场景图生成逻辑提取出来,放在线程池中运行"""
 
     def sync_generate():
@@ -635,7 +637,8 @@ async def _process_single_scene_item(aigc_clazz, goods_art_dict_info_item, produ
             return save_image_path
 
         aigc_clazz.center_paste_image(ceshi_image_path, save_image_path)
-        image_path = aigc_clazz.generateProductScene(save_image_path, product_scene_prompt, save_image_path)
+        image_path = aigc_clazz.generateProductScene(save_image_path, product_scene_prompt, save_image_path,
+                                                     product_scene_image)
         return image_path
 
     loop = asyncio.get_event_loop()
@@ -646,7 +649,8 @@ async def _process_single_scene_item(aigc_clazz, goods_art_dict_info_item, produ
         return {"success": False, "error": str(e)}
 
 
-async def _process_scene_images(aigc_clazz, run_main, return_data_check_before_detail, product_scene_prompt):
+async def _process_scene_images(aigc_clazz, run_main, return_data_check_before_detail, product_scene_prompt,
+                                product_scene_image):
     """处理场景图生成"""
     # 参数验证
     if not product_scene_prompt:
@@ -673,7 +677,7 @@ async def _process_scene_images(aigc_clazz, run_main, return_data_check_before_d
         msg_type="scene_progress",
         progress=product_scene_progress
     )
-    loop = asyncio.get_event_loop()
+    # loop = asyncio.get_event_loop()
     for goods_art_no_info in goods_dict.keys():
         goods_art_dict_info = goods_dict.get(goods_art_no_info, None)
         new_goods_dict.setdefault(goods_art_no_info, goods_art_dict_info)
@@ -705,7 +709,7 @@ async def _process_scene_images(aigc_clazz, run_main, return_data_check_before_d
             # 【修复】异步等待单个货号的 AI 处理完成
             # 这样在处理一个货号时,事件循环可以去发送其他货号的消息
             result = await _process_single_scene_item(aigc_clazz, goods_art_dict_info_item, product_scene_prompt,
-                                                      save_root_path)
+                                                      save_root_path, product_scene_image)
 
             if result["success"]:
                 goods_art_dict_info_item["场景图"] = result["path"]

+ 4 - 1
python/models.py

@@ -116,7 +116,10 @@ class HandlerDetail(BaseModel):
         default=0, description="是否生成上脚图;0否;1是"
     )
     product_scene_prompt: Optional[str] = Field(
-        default=[], description="上传的店铺,数组形式"
+        default="", description="场景图提示词"
+    )
+    product_scene_image: Optional[str] = Field(
+        default="", description="场景图参考图"
     )
     upper_footer_params: Optional[dict] = Field(
         default=None, description="上脚图参数配置"

+ 23 - 21
python/service/online_request/module_online_data.py

@@ -9,6 +9,7 @@ from PIL import Image
 import io, time
 from logger import logger
 
+
 # logger = logging.getLogger(__name__)
 
 class JsonEncoder(json.JSONEncoder):
@@ -38,7 +39,7 @@ def download_image_with_pil(url, save_path):
         return save_path
 
     except Exception as e:
-        print("保存错误",e)
+        print("保存错误", e)
         return "error"
 
 
@@ -60,7 +61,7 @@ class AIGCDataRequest(object):
         return resultData["data"]["url"]
 
     def center_paste_image(
-        self, source_image_path, output_path, width=900, ratio=(3, 4)
+            self, source_image_path, output_path, width=900, ratio=(3, 4)
     ):
         """
         将一张PNG透明图片居中粘贴到指定尺寸和比例的背景上,保持透明度
@@ -115,13 +116,14 @@ class AIGCDataRequest(object):
         source_img.close()
         return background
 
-    def generateProductScene(self, local_path, prompt, save_path):
+    def generateProductScene(self, local_path, prompt, save_path, product_scene_image):
         imageUrl = self.uploadImage(local_path)
         print("imageUrl", imageUrl)
         data = {
             "site": 1,
             "base_image": imageUrl,
             "keyword": prompt,
+            "reference_image": product_scene_image,
             "model_type": 1,
             "gemini_model": "gemini-2.5-flash-image-preview",
         }
@@ -141,7 +143,7 @@ class AIGCDataRequest(object):
             save_image_path = download_image_with_pil(image_url, save_path)
             return save_image_path
         except:
-          raise UnicornException("场景图生成失败")
+            raise UnicornException("场景图生成失败")
 
     def generateProductSceneQW(self, local_path, prompt, save_path):
         '''千问生成场景图'''
@@ -208,13 +210,13 @@ class AIGCDataRequest(object):
             data_item = data_result[0]
             status = data_item.get("status", -1)
             result_image = None
-            
+
             # 只有在完成状态下才返回图片URL
             if status == 2:  # 完成
                 result_image_urls = data_item.get("result_image_urls", [])
                 result_image_urls = [] if result_image_urls is None else result_image_urls
                 result_image = result_image_urls[0] if len(result_image_urls) > 0 else None
-                
+
             return status, result_image
         except requests.Timeout:
             print("查询进度超时")
@@ -267,7 +269,7 @@ class AIGCDataRequest(object):
         if status == -1 or (status != 2 and search_times <= 0):
             raise UnicornException("模特图生成失败")
         save_image_path = download_image_with_pil(result_image, save_path)
-        print("上脚图save_image_path",result_image, save_image_path)
+        print("上脚图save_image_path", result_image, save_image_path)
         return save_image_path
 
 
@@ -587,7 +589,7 @@ class OnlineDataRequest(object):
         print("上传商品api==>resultData", resultData)
         return resultData
 
-    def sendSocketMessage(self, code=0, msg="", data=None, device_status=2,msg_type="upload_goods_progress"):
+    def sendSocketMessage(self, code=0, msg="", data=None, device_status=2, msg_type="upload_goods_progress"):
         data = {
             "code": code,
             "msg": msg,
@@ -636,12 +638,12 @@ class OnlineDataRequest(object):
                     mainImagePath = mainImages[0]
                     imageUrl = self.uploadImage(local_path=mainImagePath)
                     skuNameJson = []
-                    skuNameJson.append({"propName":"颜色","propValue":color_name})
-                    skuNameJson.append({"propName":"尺寸","propValue":size})
+                    skuNameJson.append({"propName": "颜色", "propValue": color_name})
+                    skuNameJson.append({"propName": "尺寸", "propValue": size})
                     skuItemData = {
                         "颜色": color_name,
                         "尺寸": size,
-                        "skuPropName":color_name,
+                        "skuPropName": color_name,
                         "skuNo": sku_goods_art_no,
                         "originalPrice": float(goods_price),
                         "newSkuWeight": int(1),
@@ -650,7 +652,7 @@ class OnlineDataRequest(object):
                         "sellingPrice": float(goods_price),
                         "quantity": int(quantity),
                         "showOrder": int(skuIdx + 1),
-                        "skuNameJson":skuNameJson
+                        "skuNameJson": skuNameJson
                     }
                     skuList.append(skuItemData)
                     itemImage = {
@@ -681,16 +683,16 @@ class OnlineDataRequest(object):
                     }
                 )
                 itemSkuImageList.append({
-                        "propName": "尺寸",
-                        "isImageProp": 0,
-                        "propShowOrder": 1,
-                        "showOrder": 0,
+                    "propName": "尺寸",
+                    "isImageProp": 0,
+                    "propShowOrder": 1,
+                    "showOrder": 0,
+                    "propValue": str(size),
+                    "skuPropValueList": [{
                         "propValue": str(size),
-                        "skuPropValueList":[{
-                            "propValue": str(size),
-                            "showOrder": 1,
-                            }]
-                    })
+                        "showOrder": 1,
+                    }]
+                })
                 detailImageUrl = self.uploadImage(local_path=detail_path)
                 category_info = "流行男鞋>>休闲鞋>>时尚休闲鞋"
                 itemData = {