Browse Source

Merge branch 'cloud_configs_dir_fix' into smart-shooter-clothing

rambo 1 month ago
parent
commit
91a303e171
38 changed files with 2579 additions and 1684 deletions
  1. 608 542
      python/api.py
  2. 6 4
      python/config.ini
  3. 231 67
      python/custom_plugins/plugins/detail_template/hongqingting/detail_hongqingting2.py
  4. 216 72
      python/custom_plugins/plugins/detail_template/hongqingting/detail_hongqingting3.py
  5. 2 10
      python/custom_plugins/plugins/detail_template/huilima/detail_huilima1.py
  6. 160 88
      python/custom_plugins/plugins/detail_template/huilima/detail_huilima2.py
  7. 43 34
      python/custom_plugins/plugins/detail_template/huilima/detail_huilima3.py
  8. 46 24
      python/custom_plugins/plugins/detail_template/huilima/detail_huilima4.py
  9. 69 42
      python/custom_plugins/plugins/detail_template/huilima/detail_huilima5.py
  10. 154 148
      python/custom_plugins/plugins_mode/detail_generate_base.py
  11. 69 6
      python/databases.py
  12. 43 23
      python/detail_template_test.json
  13. 2 2
      python/detail_template_test.py
  14. 1 1
      python/mcu/BaseClass.py
  15. 3 3
      python/mcu/BlueToothMode.py
  16. 61 39
      python/mcu/DeviceControl.py
  17. 15 7
      python/mcu/ProgramItem.py
  18. 75 88
      python/mcu/RemoteControlV2.py
  19. 39 29
      python/mcu/capture/smart_shooter_class.py
  20. 8 0
      python/models.py
  21. 1 1
      python/service/auto_deal_pics/base_deal.py
  22. 10 7
      python/service/base.py
  23. 82 46
      python/service/base_deal.py
  24. 11 7
      python/service/data.py
  25. 19 13
      python/service/deal_image.py
  26. 176 45
      python/service/grenerate_main_image_test.py
  27. 2 0
      python/service/image_pic_deal.py
  28. 5 2
      python/service/match_and_cutout_mode_control/base_deal_image_v2.py
  29. 1 1
      python/service/match_and_cutout_mode_control/module_matching_photos_v2.py
  30. 1 1
      python/service/matching_photos/module_matching_photos.py
  31. 1 0
      python/service/multi_threaded_image_saving.py
  32. 113 40
      python/service/online_request/module_online_data.py
  33. 130 232
      python/service/run_main.py
  34. 21 33
      python/settings.py
  35. 5 1
      python/sockets/connect_manager.py
  36. 123 19
      python/sockets/message_handler.py
  37. 1 1
      python/sockets/socket_server.py
  38. 26 6
      python/temp.py

File diff suppressed because it is too large
+ 608 - 542
python/api.py


+ 6 - 4
python/config.ini

@@ -19,7 +19,7 @@ is_upload=true
 # 日志相关
 log_file_name=app.log
 #最大字节数
-max_bytes=102400
+max_bytes=1024000
 #备份数量
 backup_counts=3
 # 地址
@@ -43,6 +43,8 @@ right_foot_action_1 = 99
 right_foot_action_2 = 99
 stop = 9
 
-[camera_config]
-low_iso = 100
-high_iso = 6400
+; [camera_config]
+; low_iso = 100
+; high_iso = 6400
+[output_config]
+output_dir = ..\..\..\output\

+ 231 - 67
python/custom_plugins/plugins/detail_template/hongqingting/detail_hongqingting2.py

@@ -47,7 +47,7 @@ class DetailPicGet(DetailBase):
 
         self.deal_pic_func_list = [
             self.deal_pic_1,
-            self.deal_pic_2,
+            # self.deal_pic_2,
             self.deal_pic_3,
             # self.deal_pic_4,
             # self.deal_pic_5,
@@ -69,8 +69,23 @@ class DetailPicGet(DetailBase):
                                                 goods_art_no=goods_art_no_list[0],
                                                 name="后跟",
                                                 )
-        pp_jpg_1 = pp_jpg_1.resize(value=350)
-        pp_png_1 = pp_png_1.resize(value=350)
+
+
+
+
+        if pp_jpg_1.height > pp_jpg_1.width:
+            aheight =550
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        else:
+            awidth = int(pp_jpg_1.width * 0.45)
+
+
+
+
+
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         pp_bg_1 = pp_bg_1.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-200, 450))
         pp_jpg_1, pp_png_1 = self.image_one_pic(return_orign=True,
                                                 goods_art_no=goods_art_no_list[0],
@@ -79,8 +94,11 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im):
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=900)
-        pp_png_1 = pp_png_1.resize(value=900)
+
+
+
+        pp_jpg_1 = pp_jpg_1.resize(value=round(pp_bg_1.width*(800/1080)))
+        pp_png_1 = pp_png_1.resize(value=round(pp_bg_1.width*(800/1080)))
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=10,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=10,is_crop=False)
         pp_bg_1 = pp_bg_1.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(150, -250))
@@ -93,8 +111,8 @@ class DetailPicGet(DetailBase):
 
         font_cc = ImageFont.truetype(r"resources\ttf\simhei.ttf", 80)  # 颜色名
         font_gg = ImageFont.truetype(r"resources\ttf\simhei.ttf", 50)  # 商品名
-        yanseming  = self.get_text_value("颜色名") or "复古擦色"
-        shangpinming = self.get_text_value("商品名") or "户外马丁靴"
+        yanseming  = self.get_text_value("颜色名") or ""
+        shangpinming = self.get_text_value("商品名") or ""
 
         bg_img.get_text_image_advanced(
             value=(60, 310),
@@ -128,13 +146,14 @@ class DetailPicGet(DetailBase):
         bg_img = PictureProcessing(r"{}\3.jpg".format(self.root))
 
         font_gg = ImageFont.truetype(r"resources\ttf\simhei.ttf", 50)  # 商品名
-        yanseming  = self.get_text_value("颜色名") or "复古擦色"
-        shangpinming = self.get_text_value("商品名") or "户外马丁靴"
-
+        yanseming  = self.get_text_value("颜色名") or ""
+        shangpinming = self.get_text_value("商品名") or ""
+        # a="{"+yanseming+shangpinming+"}"
+        a=""
         bg_img.get_text_image_advanced(
             value=(488, 140),
             font=font_gg,
-            text="{"+yanseming+shangpinming+"}",
+            text=a,
             align="left",
             # anchor="ma",
             spacing=5,
@@ -150,8 +169,11 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == True:
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=650)
-        pp_png_1 = pp_png_1.resize(value=650)
+
+
+
+        pp_jpg_1 = pp_jpg_1.resize(value=round(bg_img.width*(650/1080)))
+        pp_png_1 = pp_png_1.resize(value=round(bg_img.width*(650/1080)))
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=15,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=15,is_crop=False)
         bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(50, 1420))
@@ -163,8 +185,8 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=650)
-        pp_png_1 = pp_png_1.resize(value=650)
+        pp_jpg_1 = pp_jpg_1.resize(value=round(bg_img.width*(650/1080)))
+        pp_png_1 = pp_png_1.resize(value=round(bg_img.width*(650/1080)))
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=-8,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=-8,is_crop=False)
         bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-100, 950))
@@ -222,27 +244,33 @@ class DetailPicGet(DetailBase):
         return bg_img
     def deal_pic_6(self):
         if self.get_text_value("模特图"):
-            hh_img = PictureProcessing(r"{}\6.jpg".format(self.root))
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=896)
-            bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height+90), (252,238,225))
-            bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
-            return bg_img
+            try:
+                hh_img = PictureProcessing(r"{}\6.jpg".format(self.root))
+                mote_img = PictureProcessing(self.get_text_value("模特图"))
+                mote_img = mote_img.resize(value=896)
+                bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height+90), (252,238,225))
+                bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
+                bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
+                return bg_img
+            except:
+              return
         else:
             return
 
     def deal_pic_7(self):
         if self.get_text_value("场景图"):
-            hh_img = PictureProcessing(r"{}\7-1.jpg".format(self.root))
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=896)
-            ff_img = PictureProcessing(r"{}\7-2.jpg".format(self.root))
-            bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height+ff_img.height), (252,238,225))
-            bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
-            bg_img = bg_img.paste_img(top_img=ff_img,base="nc", value=(0, hh_img.height+mote_img.height))
-            return bg_img
+            try:
+                hh_img = PictureProcessing(r"{}\7-1.jpg".format(self.root))
+                mote_img = PictureProcessing(self.get_text_value("场景图"))
+                mote_img = mote_img.resize(value=896)
+                ff_img = PictureProcessing(r"{}\7-2.jpg".format(self.root))
+                bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height+ff_img.height), (252,238,225))
+                bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
+                bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
+                bg_img = bg_img.paste_img(top_img=ff_img,base="nc", value=(0, hh_img.height+mote_img.height))
+                return bg_img
+            except:
+              return
         else:
             return
     def deal_pic_8(self):
@@ -261,29 +289,51 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
             pp_png_1 = pp_png_1.transpose()
             pp_jpg_1 = pp_jpg_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=950)
-        pp_png_1 = pp_png_1.resize(value=950)
+
+        pp_jpg_1 = pp_jpg_1.resize(value=int(round(bg_img.width * 660 / 1080)))
+        pp_png_1 = pp_png_1.resize(value=int(round(bg_img.width * 660 / 1080)))
+
+
+        pw=pp_png_1.width
+        ph=pp_png_1.height
 
         aaa_img = aaa_img.paste_img(top_img=pp_png_1,base="cc", value=(0, 0))
 
+
         pp_png_1 = aaa_img.rotate(15)
+        print("811111111111111111")
+        print(ph/pw)
+        if (ph/pw)>1:
+            posy=(-1)*int(round(bg_img.height * 0.27))
+        elif (ph/pw)>0.8:
+            posy=(-1)*int(round(bg_img.height * 0.225))
+        else:
+            posy=(-1)*int(round(bg_img.height * 0.20))
+        posx=-10
+
+        # posy=int(round(bg_img.height * 0.01))
+        # print(posy)
+
         bg_img = bg_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_png_1,
-            base="cs",
-            value=(-20, 40),
+            base="cc",
+            value=(posx, posy),
             top_png_img=pp_png_1,
         )
 
-        hover_img = PictureProcessing(r"{}\8-1.png".format(self.root))
-        bg_img = bg_img.to_overlay_pic_advance(
-            mode="pixel",
-            top_img=hover_img,
-            base="nc",
-            value=(0, -1),
-            top_png_img=hover_img,
-        )
-        return bg_img
+        bg_img1 = PictureProcessing("RGB", (bg_img.width, 1080), (255,255,255))
+        bg_img1 = bg_img1.paste_img(top_img=bg_img,base="nc", value=(0, 0))
+
+        # hover_img = PictureProcessing(r"{}\8-1.png".format(self.root))
+        # bg_img = bg_img.to_overlay_pic_advance(
+        #     mode="pixel",
+        #     top_img=hover_img,
+        #     base="nc",
+        #     value=(0, -1),
+        #     top_png_img=hover_img,
+        # )
+        return bg_img1
 
     def deal_pic_9(self):
         goods_art_no_list = list(self.data.keys())
@@ -420,13 +470,27 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
             pp_png_1 = pp_png_1.transpose()
             pp_jpg_1 = pp_jpg_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=500)
-        pp_png_1 = pp_png_1.resize(value=500)
+
+        posy=2325
+        if pp_jpg_1.height > pp_jpg_1.width:
+            aheight =350
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        else:
+            if pp_jpg_1.height > (pp_jpg_1.width/2):
+                awidth = int(bg_img.width * 0.4)
+            else:
+                awidth = int(bg_img.width * 0.4)
+                posy=2380
+
+
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         bg_img = bg_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
             base="cs",
-            value=(-40, 2300),
+            value=(-15, posy),
             top_png_img=pp_png_1,
         )
 
@@ -806,17 +870,22 @@ class DetailPicGet(DetailBase):
         # item1
         item_img = PictureProcessing("RGBA", (header_img.width, 760), (255,255,255))
 
+
+
         if len(goods_art_no_list)==3:
             pp_jpg_1, pp_png_1 = self.image_one_pic(
                 return_orign=True,
                 goods_art_no=goods_art_no_list[2],
                 name="俯视",
             )
+            aheight =400
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
             if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
                 pp_png_1 = pp_png_1.transpose()
                 pp_jpg_1 = pp_jpg_1.transpose()
-            pp_jpg_1 = pp_jpg_1.resize(value=460)
-            pp_png_1 = pp_png_1.resize(value=460)
+            pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+            pp_png_1 = pp_png_1.resize(value=awidth)
             item_img = item_img.to_overlay_pic_advance(
                 mode="pixel",
                 top_img=pp_jpg_1,
@@ -830,11 +899,14 @@ class DetailPicGet(DetailBase):
                 goods_art_no=goods_art_no_list[1],
                 name="俯视",
             )
+            aheight =400
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
             if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
                 pp_png_1 = pp_png_1.transpose()
                 pp_jpg_1 = pp_jpg_1.transpose()
-            pp_jpg_1 = pp_jpg_1.resize(value=460)
-            pp_png_1 = pp_png_1.resize(value=460)
+            pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+            pp_png_1 = pp_png_1.resize(value=awidth)
             item_img = item_img.to_overlay_pic_advance(
                 mode="pixel",
                 top_img=pp_jpg_1,
@@ -848,11 +920,14 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="俯视",
         )
+        aheight =400
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
             pp_png_1 = pp_png_1.transpose()
             pp_jpg_1 = pp_jpg_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=460)
-        pp_png_1 = pp_png_1.resize(value=460)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -889,8 +964,12 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="后跟",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=360)
-        pp_png_1 = pp_png_1.resize(value=360)
+
+        aheight =400
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -928,8 +1007,12 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im)== True:
             pp_png_1 = pp_png_1.transpose()
             pp_jpg_1 = pp_jpg_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=530)
-        pp_png_1 = pp_png_1.resize(value=530)
+
+        aheight =380
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -964,28 +1047,47 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="内里",
         )
+
+
+
         pp_jpg_1 = pp_jpg_1.resize(value=530)
         pp_png_1 = pp_png_1.resize(value=530)
+
+
+        ty=0
+        if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+            ty=1
+
+
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=90,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=90,is_crop=False)
 
+        if ty==1:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+
+
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_png_1,
             base="cs",
-            value=(-120, -50),
-            top_png_img=pp_png_1,
-        )
-        pp_jpg_1 = pp_jpg_1.transpose()
-        pp_png_1 = pp_png_1.transpose()
-        item_img = item_img.to_overlay_pic_advance(
-            mode="pixel",
-            top_img=pp_png_1,
-            base="cs",
-            value=(120, -50),
+            value=(0, -50),
             top_png_img=pp_png_1,
         )
 
+
+        # pp_jpg_1 = pp_jpg_1.transpose()
+        # pp_png_1 = pp_png_1.transpose()
+        # item_img = item_img.to_overlay_pic_advance(
+        #     mode="pixel",
+        #     top_img=pp_png_1,
+        #     base="cs",
+        #     value=(120, -50),
+        #     top_png_img=pp_png_1,
+        # )
+
         font_hei = ImageFont.truetype(r"resources\ttf\simhei.ttf", 24)
         item_img.get_text_image_advanced(
             value=(500, 600),
@@ -1010,5 +1112,67 @@ class DetailPicGet(DetailBase):
 
     def deal_pic_12(self):
         # 背景图
+        goods_art_no_list = list(self.data.keys())
+        # 背景图
         bg_img = PictureProcessing(r"{}\12.jpg".format(self.root))
+
+        item_img = PictureProcessing("RGB", (404, 334), (247,247,247))
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=item_img,
+            base="es",
+            value=(150, 180+2158),
+            top_png_img=item_img,
+        )
+
+
+        # item4
+        item_img = PictureProcessing("RGBA", (bg_img.width, 760), (255,255,255))
+
+
+
+        pp_jpg_1, pp_png_1 = self.image_one_pic(
+            return_orign=True,
+            goods_art_no=goods_art_no_list[0],
+            name="内里",
+        )
+
+
+
+        aheight =100
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
+
+        ty=0
+        if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+            ty=1
+
+        pp_jpg_1=pp_jpg_1.rotate_advance(doge=90,is_crop=False)
+        pp_png_1=pp_png_1.rotate_advance(doge=90,is_crop=False)
+
+
+        if ty==1:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=pp_png_1,
+            base="es",
+            value=(-60+50,50+2158),
+            top_png_img=pp_png_1,
+        )
+        pp_jpg_1 = pp_jpg_1.transpose()
+        pp_png_1 = pp_png_1.transpose()
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=pp_png_1,
+            base="es",
+            value=(60+50, 50+2158),
+            top_png_img=pp_png_1,
+        )
         return bg_img

+ 216 - 72
python/custom_plugins/plugins/detail_template/hongqingting/detail_hongqingting3.py

@@ -119,17 +119,28 @@ class DetailPicGet(DetailBase):
 
         # aaa_img = PictureProcessing("RGBA", (pp_jpg_1.width*1.2, pp_jpg_1.height*1.2), (255,255,255,0))
         #
-        pp_png_1 = pp_png_1.resize(value=850)
-        pp_jpg_1 = pp_jpg_1.resize(value=850)
+        ph=pp_png_1.height
+        pw=pp_png_1.width
+        if (ph/pw)>0.8:
+            aheight =600
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        else:
+            aheight =450
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_png_1 = pp_png_1.resize(value=awidth)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
         #
         # aaa_img = aaa_img.paste_img(top_img=pp_png_1,base="cc", value=(0, 0))
 
+
         # pp_png_1 = aaa_img.rotate(0)
         bg_img = bg_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
-            base="cs",
-            value=(-200, 300),
+            base="cn",
+            value=(-200, round(bg_img.height*0.65)),
             top_png_img=pp_png_1,
         )
 
@@ -141,8 +152,8 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_2.im)== False:
             pp_png_2 = pp_png_2.transpose()
             pp_jpg_2 = pp_jpg_2.transpose()
-        pp_png_2 = pp_png_2.resize(value=850)
-        pp_jpg_2 = pp_jpg_2.resize(value=850)
+        pp_png_2 = pp_png_2.resize(value=awidth)
+        pp_jpg_2 = pp_jpg_2.resize(value=awidth)
         # aaa_img = PictureProcessing("RGBA", (pp_jpg_2.width*1.2, pp_jpg_2.height*1.2), (255,255,255,0))
         #
         # aaa_img = aaa_img.paste_img(top_img=pp_png_2,base="cc", value=(0, 0))
@@ -152,7 +163,7 @@ class DetailPicGet(DetailBase):
             mode="pixel",
             top_img=pp_jpg_2,
             base="cs",
-            value=(200, 850),
+            value=(200, 900),
             top_png_img=pp_png_2,
         )
         return bg_img
@@ -187,8 +198,8 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=850)
-        pp_png_1 = pp_png_1.resize(value=850)
+        pp_jpg_1 = pp_jpg_1.resize(value=round(bg_img.width*(850/bg_img.width)))
+        pp_png_1 = pp_png_1.resize(value=round(bg_img.width*(850/bg_img.width)))
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=-35,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=-35,is_crop=False)
         bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(0, 100))
@@ -247,11 +258,17 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=850)
-        pp_png_1 = pp_png_1.resize(value=850)
+        # pp_jpg_1 = pp_jpg_1.resize(value=850)
+        # pp_png_1 = pp_png_1.resize(value=850)
+        aheight =650
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
+
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=25,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=25,is_crop=False)
-        bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-250, -120))
+        bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-250, -240))
 
         pp_jpg_1, pp_png_1 = self.image_one_pic(return_orign=True,
                                                 goods_art_no=goods_art_no_list[0],
@@ -260,8 +277,8 @@ class DetailPicGet(DetailBase):
         if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == True:
             pp_jpg_1 = pp_jpg_1.transpose()
             pp_png_1 = pp_png_1.transpose()
-        pp_jpg_1 = pp_jpg_1.resize(value=800)
-        pp_png_1 = pp_png_1.resize(value=800)
+        pp_jpg_1 = pp_jpg_1.resize(value=round(bg_img.width*(800/bg_img.width)))
+        pp_png_1 = pp_png_1.resize(value=round(bg_img.width*(800/bg_img.width)))
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=30,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=30,is_crop=False)
         bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(220, -250))
@@ -317,36 +334,52 @@ class DetailPicGet(DetailBase):
                                                 goods_art_no=goods_art_no_list[0],
                                                 name="侧视",
                                                 )
-        pp_jpg_1 = pp_jpg_1.resize(value=850)
-        pp_png_1 = pp_png_1.resize(value=850)
+        pp_jpg_1 = pp_jpg_1.resize(value=round(bg_img.width*(850/bg_img.width)))
+        pp_png_1 = pp_png_1.resize(value=round(bg_img.width*(850/bg_img.width)))
+        pw=pp_png_1.width
+        ph=pp_png_1.height
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=22,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=22,is_crop=False)
-        bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-50, -230))
+
+        if (ph/pw)>0.8:
+            print(555555555551)
+            print(ph/pw)
+            posy=(-1)*round(bg_img.height*0.12)
+        else:
+            print(555555555552)
+            posy=(-1)*round(bg_img.height*0.16)
+        bg_img = bg_img.to_overlay_pic_advance(top_img=pp_jpg_1, top_png_img=pp_png_1, base="cs",value=(-50,posy ))
 
         detailed_images.append(bg_img)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
     def deal_pic_6(self):
         if self.get_text_value("模特图"):
-            hh_img = PictureProcessing(r"{}\6.jpg".format(self.root))
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1400)
-            bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
-            return bg_img
+            try:
+                hh_img = PictureProcessing(r"{}\6.jpg".format(self.root))
+                mote_img = PictureProcessing(self.get_text_value("模特图"))
+                mote_img = mote_img.resize(value=1400)
+                bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height), (255,255,255))
+                bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
+                bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
+                return bg_img
+            except:
+              return
         else:
             return
 
     def deal_pic_7(self):
         if self.get_text_value("场景图"):
-            hh_img = PictureProcessing(r"{}\7.jpg".format(self.root))
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1400)
-            bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
-            return bg_img
+            try:
+                hh_img = PictureProcessing(r"{}\7.jpg".format(self.root))
+                mote_img = PictureProcessing(self.get_text_value("场景图"))
+                mote_img = mote_img.resize(value=1400)
+                bg_img = PictureProcessing("RGB", (hh_img.width, hh_img.height+mote_img.height), (255,255,255))
+                bg_img = bg_img.paste_img(top_img=hh_img,base="nc", value=(0, 0))
+                bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, hh_img.height))
+                return bg_img
+            except:
+              return
         else:
             return
 
@@ -371,8 +404,16 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="俯视",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=660)
-        pp_png_1 = pp_png_1.resize(value=660)
+
+        if pp_jpg_1.height > pp_jpg_1.width:
+            aheight =650
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        else:
+            awidth=round(0.52*bg_img.width)
+
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         bg_img = bg_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -681,7 +722,7 @@ class DetailPicGet(DetailBase):
             mode="pixel",
             top_img=all_color_pp,
             base="cs",
-            value=(0, 350),
+            value=(0, 250),
             top_png_img=all_color_pp,
         )
 
@@ -710,8 +751,11 @@ class DetailPicGet(DetailBase):
                 goods_art_no=goods_art_no_list[2],
                 name="俯视",
             )
-            pp_jpg_1 = pp_jpg_1.resize(value=460)
-            pp_png_1 = pp_png_1.resize(value=460)
+            aheight =400
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+            pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+            pp_png_1 = pp_png_1.resize(value=awidth)
             item_img = item_img.to_overlay_pic_advance(
                 mode="pixel",
                 top_img=pp_jpg_1,
@@ -725,8 +769,11 @@ class DetailPicGet(DetailBase):
                 goods_art_no=goods_art_no_list[1],
                 name="俯视",
             )
-            pp_jpg_1 = pp_jpg_1.resize(value=460)
-            pp_png_1 = pp_png_1.resize(value=460)
+            aheight =400
+            # 等比计算目标宽度
+            awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+            pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+            pp_png_1 = pp_png_1.resize(value=awidth)
             item_img = item_img.to_overlay_pic_advance(
                 mode="pixel",
                 top_img=pp_jpg_1,
@@ -740,8 +787,11 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="俯视",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=460)
-        pp_png_1 = pp_png_1.resize(value=460)
+        aheight =400
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -778,29 +828,35 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="后跟",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=460)
-        pp_png_1 = pp_png_1.resize(value=460)
-        item_img = item_img.to_overlay_pic_advance(
-            mode="pixel",
-            top_img=pp_jpg_1,
-            base="cs",
-            value=(60, 260),
-            top_png_img=pp_png_1,
-        )
-        pp_jpg_1, pp_png_1 = self.image_one_pic(
-            return_orign=True,
-            goods_art_no=goods_art_no_list[0],
-            name="后跟",
-        )
-        pp_jpg_1 = pp_jpg_1.resize(value=460)
-        pp_png_1 = pp_png_1.resize(value=460)
+        aheight =400
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
             base="cs",
-            value=(-60, 220),
+            value=(0, 240),
             top_png_img=pp_png_1,
         )
+        # pp_jpg_1, pp_png_1 = self.image_one_pic(
+        #     return_orign=True,
+        #     goods_art_no=goods_art_no_list[0],
+        #     name="后跟",
+        # )
+        # aheight =450
+        # # 等比计算目标宽度
+        # awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        # pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        # pp_png_1 = pp_png_1.resize(value=awidth)
+        # item_img = item_img.to_overlay_pic_advance(
+        #     mode="pixel",
+        #     top_img=pp_jpg_1,
+        #     base="cs",
+        #     value=(-60, 220),
+        #     top_png_img=pp_png_1,
+        # )
 
         item_img.get_text_image_advanced(
             value=(520, 600),
@@ -828,8 +884,12 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="侧视",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=530)
-        pp_png_1 = pp_png_1.resize(value=530)
+
+        aheight =350
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_jpg_1,
@@ -863,27 +923,45 @@ class DetailPicGet(DetailBase):
             goods_art_no=goods_art_no_list[0],
             name="内里",
         )
-        pp_jpg_1 = pp_jpg_1.resize(value=530)
-        pp_png_1 = pp_png_1.resize(value=530)
+
+
+        awidth = 200
+        aheight = int(pp_jpg_1.width * awidth / pp_jpg_1.height)
+
+
+        pp_jpg_1 = pp_jpg_1.resize(value=aheight)
+        pp_png_1 = pp_png_1.resize(value=aheight)
+
+        ty=0
+        if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+            ty=1
+
         pp_jpg_1=pp_jpg_1.rotate_advance(doge=90,is_crop=False)
         pp_png_1=pp_png_1.rotate_advance(doge=90,is_crop=False)
 
+
+        if ty==1:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+
         item_img = item_img.to_overlay_pic_advance(
             mode="pixel",
             top_img=pp_png_1,
             base="cs",
-            value=(-120, -50),
-            top_png_img=pp_png_1,
-        )
-        pp_jpg_1 = pp_jpg_1.transpose()
-        pp_png_1 = pp_png_1.transpose()
-        item_img = item_img.to_overlay_pic_advance(
-            mode="pixel",
-            top_img=pp_png_1,
-            base="cs",
-            value=(120, -50),
+            value=(0, -70),
             top_png_img=pp_png_1,
         )
+        # pp_jpg_1 = pp_jpg_1.transpose()
+        # pp_png_1 = pp_png_1.transpose()
+        # item_img = item_img.to_overlay_pic_advance(
+        #     mode="pixel",
+        #     top_img=pp_png_1,
+        #     base="cs",
+        #     value=(120, -50),
+        #     top_png_img=pp_png_1,
+        # )
 
         item_img.get_text_image_advanced(
             value=(600, 600),
@@ -905,9 +983,75 @@ class DetailPicGet(DetailBase):
         )
 
 
-        return bg_img 
+        return bg_img
 
     def deal_pic_12(self):
+
+        goods_art_no_list = list(self.data.keys())
         # 背景图
         bg_img = PictureProcessing(r"{}\12.jpg".format(self.root))
+
+        item_img = PictureProcessing("RGB", (510, 440), (247,247,247))
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=item_img,
+            base="es",
+            value=(190, 240),
+            top_png_img=item_img,
+        )
+
+
+        # item4
+        item_img = PictureProcessing("RGBA", (bg_img.width, 760), (255,255,255))
+
+
+
+        pp_jpg_1, pp_png_1 = self.image_one_pic(
+            return_orign=True,
+            goods_art_no=goods_art_no_list[0],
+            name="内里",
+        )
+
+
+
+        aheight =170
+        # 等比计算目标宽度
+        awidth = int(pp_jpg_1.width * aheight / pp_jpg_1.height)
+        pp_jpg_1 = pp_jpg_1.resize(value=awidth)
+        pp_png_1 = pp_png_1.resize(value=awidth)
+
+        ty=0
+        if self.check_shoe_is_right_by_pixel(im=pp_png_1.im) == False:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+            ty=1
+
+        pp_jpg_1=pp_jpg_1.rotate_advance(doge=90,is_crop=False)
+        pp_png_1=pp_png_1.rotate_advance(doge=90,is_crop=False)
+
+
+        if ty==1:
+            pp_jpg_1 = pp_jpg_1.transpose()
+            pp_png_1 = pp_png_1.transpose()
+
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=pp_png_1,
+            base="es",
+            value=(-100-0,30),
+            top_png_img=pp_png_1,
+        )
+        pp_jpg_1 = pp_jpg_1.transpose()
+        pp_png_1 = pp_png_1.transpose()
+        bg_img = bg_img.to_overlay_pic_advance(
+            mode="pixel",
+            top_img=pp_png_1,
+            base="es",
+            value=(100-0, 30),
+            top_png_img=pp_png_1,
+        )
+
+
+
+
         return bg_img

+ 2 - 10
python/custom_plugins/plugins/detail_template/huilima/detail_huilima1.py

@@ -134,21 +134,13 @@ class DetailPicGet(DetailBase):
     #模特图
     def deal_pic_1_2(self):
         if self.get_text_value("模特图"):
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1200)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("模特图"),resize=1200)
         else:
             return
     #场景图
     def deal_pic_1_3(self):
         if self.get_text_value("场景图"):
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1200)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("场景图"),resize=1200)
         else:
             return
 

+ 160 - 88
python/custom_plugins/plugins/detail_template/huilima/detail_huilima2.py

@@ -4,6 +4,7 @@
 2、整理所有相关的图片作为素材图
 3、按要求进行拼接
 """
+
 import os
 from PIL import ImageFont
 import sys
@@ -30,15 +31,31 @@ template_name = "huilima-2"
 
 # 皮鞋模板
 
+
 class DetailPicGet(DetailBase):
     need_view = ["俯视", "侧视", "后跟", "鞋底", "内里"]
     root = r"{}\resources\detail_temp\huilima\2".format(os.getcwd())
 
-    def __init__(self, goods_no, goods_no_value: dict, out_put_dir, windows=None, test=False, excel_data=None,
-                 assigned_page_list=None, **kwargs):
-
-        super().__init__(goods_no, goods_no_value, out_put_dir, windows=windows, excel_data=excel_data,
-                         assigned_page_list=assigned_page_list)
+    def __init__(
+        self,
+        goods_no,
+        goods_no_value: dict,
+        out_put_dir,
+        windows=None,
+        test=False,
+        excel_data=None,
+        assigned_page_list=None,
+        **kwargs
+    ):
+
+        super().__init__(
+            goods_no,
+            goods_no_value,
+            out_put_dir,
+            windows=windows,
+            excel_data=excel_data,
+            assigned_page_list=assigned_page_list,
+        )
 
         self.template_name = template_name
         self.root = r"{}\resources\detail_temp\huilima\2".format(os.getcwd())
@@ -70,7 +87,11 @@ class DetailPicGet(DetailBase):
         img = self.add_pic(detailed_images)
         if img:
             self.create_folder(r"{}/{}".format(self.out_put_dir, template_name))
-            img.save(r"{}/{}/{}.jpg".format(self.out_put_dir, template_name, self.goods_no, format="JPEG"))
+            img.save(
+                r"{}/{}/{}.jpg".format(
+                    self.out_put_dir, template_name, self.goods_no, format="JPEG"
+                )
+            )
             img.show()
 
     # 斜视图展示
@@ -80,13 +101,18 @@ class DetailPicGet(DetailBase):
         detailed_images.append(pp_bg)
         goods_art_no_list = list(self.data.keys())
         # ----粘贴俯视图
-        pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no_list[0],
-                                                color_name="俯视",
-                                                bg_color=self.base_bg_color)
+        pp_jpg = self.get_overlay_pic_from_dict(
+            goods_art_no=goods_art_no_list[0],
+            color_name="俯视",
+            bg_color=self.base_bg_color,
+        )
         pp_jpg = pp_jpg.resize(value=1098)
         pp_jpg = pp_jpg.paste_img_invert(
-            top_img=PictureProcessing("RGB", (1600, pp_jpg.height + 100), self.base_bg_color),
-            base="cc")
+            top_img=PictureProcessing(
+                "RGB", (1600, pp_jpg.height + 100), self.base_bg_color
+            ),
+            base="cc",
+        )
         detailed_images.append(pp_jpg)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
@@ -104,89 +130,94 @@ class DetailPicGet(DetailBase):
         detailed_images = []
         goods_art_no_list = list(self.data.keys())
         # =====添加侧视图
-        pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no_list[0],
-                                                color_name="侧视",
-                                                bg_color=self.base_bg_color)
+        pp_jpg = self.get_overlay_pic_from_dict(
+            goods_art_no=goods_art_no_list[0],
+            color_name="侧视",
+            bg_color=self.base_bg_color,
+        )
         pp_jpg = pp_jpg.resize(value=1098)
         pp_jpg = pp_jpg.paste_img_invert(
-            top_img=PictureProcessing("RGB", (1600, pp_jpg.height + 100), self.base_bg_color),
-            base="cc")
+            top_img=PictureProcessing(
+                "RGB", (1600, pp_jpg.height + 100), self.base_bg_color
+            ),
+            base="cc",
+        )
         detailed_images.append(pp_jpg)
 
         font_1 = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 48)  # 颜色名称
         # =====添加鞋面描述
         pp_bg_2 = PictureProcessing(r"{}\7.jpg".format(self.root))
         text = self.get_text_value("提示1主标题")
-        if text:
-            _pp = PictureProcessing().get_text_image_advanced(
-                font=font_1,
-                text=text,
-                fill=(122, 122, 122),
-                return_mode="min_image",
-            )
-            pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=(143, 166), base="ne")
+        if not text:
+            text = "匠心鞋面,质感出众,型格自现"
+        _pp = PictureProcessing().get_text_image_advanced(
+            font=font_1,
+            text=text,
+            fill=(122, 122, 122),
+            return_mode="min_image",
+        )
+        pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=(143, 166), base="ne")
         detailed_images.append(pp_bg_2)
 
-        pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no_list[0],
-                                                color_name="俯视",
-                                                bg_color=self.base_bg_color)
+        pp_jpg = self.get_overlay_pic_from_dict(
+            goods_art_no=goods_art_no_list[0],
+            color_name="俯视",
+            bg_color=self.base_bg_color,
+        )
         pp_jpg = pp_jpg.transpose(mode="left_right")
         pp_jpg = pp_jpg.resize(value=2210)
         pp_jpg = pp_jpg.paste_img_invert(
-            top_img=PictureProcessing("RGB", (1600, pp_jpg.height + 200), self.base_bg_color),
+            top_img=PictureProcessing(
+                "RGB", (1600, pp_jpg.height + 200), self.base_bg_color
+            ),
             base="en",
-            value=(149, 0)
+            value=(149, 0),
         )
         detailed_images.append(pp_jpg)
         # =====添加内里图
         pp_bg_3 = PictureProcessing(r"{}\8.jpg".format(self.root))
         text = self.get_text_value("提示2主标题")
-        if text:
-            _pp = PictureProcessing().get_text_image_advanced(
-                font=font_1,
-                text=text,
-                fill=(122, 122, 122),
-                return_mode="min_image",
-            )
-            pp_bg_3 = pp_bg_3.paste_img(top_img=_pp, value=(143, 166), base="nw")
+        if not text:
+            text = "透气鞋面配皮内里,干爽舒适一整天"
+        _pp = PictureProcessing().get_text_image_advanced(
+            font=font_1,
+            text=text,
+            fill=(122, 122, 122),
+            return_mode="min_image",
+        )
+        pp_bg_3 = pp_bg_3.paste_img(top_img=_pp, value=(143, 166), base="nw")
         detailed_images.append(pp_bg_3)
 
-        pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no_list[0],
-                                                color_name="内里",
-                                                bg_color=self.base_bg_color)
+        pp_jpg = self.get_overlay_pic_from_dict(
+            goods_art_no=goods_art_no_list[0],
+            color_name="内里",
+            bg_color=self.base_bg_color,
+        )
         pp_jpg = pp_jpg.resize(value=2130)
         pp_jpg = pp_jpg.paste_img_invert(
-            top_img=PictureProcessing("RGB", (1600, pp_jpg.height + 100), self.base_bg_color),
+            top_img=PictureProcessing(
+                "RGB", (1600, pp_jpg.height + 100), self.base_bg_color
+            ),
             base="wc",
-            value=(294, 0)
+            value=(294, 0),
         )
         detailed_images.append(pp_jpg)
 
         return PictureProcessing(im=self.add_pic(detailed_images))
 
-
-    #模特图
+    # 模特图
     def deal_pic_3_2(self):
         if self.get_text_value("模特图"):
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("模特图"),resize=1600)
         else:
             return
-    #场景图
+    # 场景图
     def deal_pic_3_3(self):
         if self.get_text_value("场景图"):
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+           return self.concatAigcImage(self.get_text_value("场景图"),resize=1600)
         else:
             return
 
-
     # 展示产品信息和颜色图
     def deal_pic_4(self):
         detailed_images = []
@@ -194,23 +225,50 @@ class DetailPicGet(DetailBase):
         #  添加基础信息
         font_1 = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 46)  # 颜色名称
         text_list = [
-            {"text": "产品名称", "pos": (294, 531)},
-            {"text": "产地", "pos": (1235, 531)},
-            {"text": "鞋面材质", "pos": (429, 623)},
-            {"text": "鞋底材质", "pos": (1235, 623)},
-            {"text": "设计理念", "pos": (294, 721)},
+            {
+                "text": "产品名称",
+                "temp_text": "商品标题",
+                "default_value": "",
+                "pos": (294, 531),
+            },
+            {"text": "产地", "temp_text": "", "default_value": "浙江温州", "pos": (1235, 531)},
+            {
+                "text": "鞋面材质",
+                "temp_text": "商品面料",
+                "default_value": "",
+                "pos": (429, 623),
+            },
+            {
+                "text": "鞋底材质",
+                "temp_text": "商品鞋底",
+                "default_value": "",
+                "pos": (1235, 623),
+            },
+            {
+                "text": "设计理念",
+                "temp_text": "",
+                "default_value": "",
+                "pos": (294, 721),
+            },
         ]
         pp_bg_1 = PictureProcessing(r"{}\9.jpg".format(self.root))
         for text_data in text_list:
             text = self.get_text_value(text_data["text"])
-            if text:
-                _pp = PictureProcessing().get_text_image_advanced(
-                    font=font_1,
-                    text=text,
-                    fill=(136, 136, 136),
-                    return_mode="min_image",
-                )
-                pp_bg_1 = pp_bg_1.paste_img(top_img=_pp, value=text_data["pos"])
+            if not text:
+                if text_data["temp_text"]:
+                    text = self.get_text_value(text_data["temp_text"])
+                if not text:
+                    text = text_data["default_value"]
+                if not text:
+                    continue
+            text = text[:13] + "..." if len(text) > 15 else text
+            _pp = PictureProcessing().get_text_image_advanced(
+                font=font_1,
+                text=text,
+                fill=(136, 136, 136),
+                return_mode="min_image",
+            )
+            pp_bg_1 = pp_bg_1.paste_img(top_img=_pp, value=text_data["pos"])
 
         detailed_images.append(pp_bg_1)
         # =======添加各个颜色====多余高度需要剪裁
@@ -221,32 +279,41 @@ class DetailPicGet(DetailBase):
         for goods_art_no_dict in self.goods_no_value["货号资料"]:
             color_name = goods_art_no_dict["颜色名称"]
             goods_art_no = goods_art_no_dict["货号"]
-            pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no,
-                                                    color_name="侧视",
-                                                    bg_color=self.base_bg_color)
+            pp_jpg = self.get_overlay_pic_from_dict(
+                goods_art_no=goods_art_no,
+                color_name="侧视",
+                bg_color=self.base_bg_color,
+            )
             pp_jpg = pp_jpg.resize(value=390)
 
             pp_jpg = pp_jpg.paste_img_invert(
-                top_img=PictureProcessing("RGBA", (pp_jpg.width, pp_jpg.height + 70), (255, 255, 255, 0)),
-                base="nw"
+                top_img=PictureProcessing(
+                    "RGBA", (pp_jpg.width, pp_jpg.height + 70), (255, 255, 255, 0)
+                ),
+                base="nw",
+            )
+            text_image = pp_bg_2.get_text_image_advanced(
+                font=font_2,
+                text="{} / COLOR".format(color_name),
+                fill=(0, 0, 0),
+                return_mode="min_image",
             )
-            text_image = pp_bg_2.get_text_image_advanced(font=font_2,
-                                                         text="{} / COLOR".format(color_name),
-                                                         fill=(0, 0, 0),
-                                                         return_mode="min_image")
 
             pp_jpg = pp_jpg.paste_img(top_img=text_image, base="sc", value=(0, 10))
             color_pic_list_1.append(pp_jpg)
 
         # 颜色列表进行等分展示
-        all_color_pp = PictureProcessing().horizontal_distribution(color_pic_list_1, bg_width=1114,
-                                                                   line_spacing=10,
-                                                                   number_per_row=2)
+        all_color_pp = PictureProcessing().horizontal_distribution(
+            color_pic_list_1, bg_width=1114, line_spacing=10, number_per_row=2
+        )
 
         all_color_pp = all_color_pp.paste_img_invert(
-            top_img=PictureProcessing("RGB", (1600, all_color_pp.height + 100), self.base_bg_color),
+            top_img=PictureProcessing(
+                "RGB", (1600, all_color_pp.height + 100), self.base_bg_color
+            ),
             base="cc",
-            value=(0, 0))
+            value=(0, 0),
+        )
         detailed_images.append(all_color_pp)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
@@ -262,17 +329,22 @@ class DetailPicGet(DetailBase):
             color_name = goods_art_no_dict["颜色名称"]
             goods_art_no = goods_art_no_dict["货号"]
             for index, view_name in enumerate(view_list):
-                pp_jpg = self.get_overlay_pic_from_dict(goods_art_no=goods_art_no,
-                                                        color_name=view_name,
-                                                        bg_color=self.base_bg_color)
+                pp_jpg = self.get_overlay_pic_from_dict(
+                    goods_art_no=goods_art_no,
+                    color_name=view_name,
+                    bg_color=self.base_bg_color,
+                )
                 if view_name == "后跟":
                     pp_jpg = pp_jpg.resize(value=600)
                 else:
                     pp_jpg = pp_jpg.resize(value=1202)
                 pp_jpg = pp_jpg.paste_img_invert(
-                    top_img=PictureProcessing("RGB", (1600, pp_jpg.height + 100), self.base_bg_color),
+                    top_img=PictureProcessing(
+                        "RGB", (1600, pp_jpg.height + 100), self.base_bg_color
+                    ),
                     base="cc",
-                    value=(0, 0))
+                    value=(0, 0),
+                )
                 detailed_images.append(pp_jpg)
 
         return PictureProcessing(im=self.add_pic(detailed_images))

+ 43 - 34
python/custom_plugins/plugins/detail_template/huilima/detail_huilima3.py

@@ -147,14 +147,18 @@ class DetailPicGet(DetailBase):
         pp_bg_2 = PictureProcessing(r"{}\3.jpg".format(self.root))
         font_1 = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 60)  # 颜色名称
         text = self.get_text_value("标题")
-        if text:
-            _pp = PictureProcessing().get_text_image_advanced(
-                font=font_1,
-                text=text,
-                fill=(255, 255, 255),
-                return_mode="min_image",
-            )
-            pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=(0, 362), base="nc")
+        if not text:
+            text = self.get_text_value("商品标题")
+            text = text[:6] if len(text) > 6 else text
+        if not text:
+            text = "复古运动鞋"
+        _pp = PictureProcessing().get_text_image_advanced(
+            font=font_1,
+            text=text,
+            fill=(255, 255, 255),
+            return_mode="min_image",
+        )
+        pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=(0, 362), base="nc")
         detailed_images.append(pp_bg_2)
 
         return PictureProcessing(im=self.add_pic(detailed_images))
@@ -179,48 +183,50 @@ class DetailPicGet(DetailBase):
         # 介绍卖点
         font_1 = ImageFont.truetype(r"resources\ttf\puhui\Medium.ttf", 60)  # 颜色名称
         text_list = [
-            {"text": "卖点1标题", "pos": (0, 58)},
-            {"text": "卖点2标题", "pos": (0, 283)},
-            {"text": "卖点3标题", "pos": (0, 505)},
+            {
+                "text": "卖点1标题",
+                "default": "轻盈缓震,健步如飞,久走不累",
+                "pos": (0, 58),
+            },
+            {
+                "text": "卖点2标题",
+                "default": "透气网面,干爽舒适,告别闷热",
+                "pos": (0, 283),
+            },
+            {
+                "text": "卖点3标题",
+                "default": "柔韧大底,灵活弯折,自在穿行",
+                "pos": (0, 505),
+            },
         ]
         pp_bg_2 = PictureProcessing(r"{}\6.jpg".format(self.root))
         for text_data in text_list:
             text = self.get_text_value(text_data["text"])
-            if text:
-                _pp = PictureProcessing().get_text_image_advanced(
-                    font=font_1,
-                    text=text,
-                    fill=(0, 0, 0),
-                    return_mode="min_image",
-                )
-                pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=text_data["pos"], base="nc")
+            if not text:
+                text = text_data["default"]
+            _pp = PictureProcessing().get_text_image_advanced(
+                font=font_1,
+                text=text,
+                fill=(0, 0, 0),
+                return_mode="min_image",
+            )
+            pp_bg_2 = pp_bg_2.paste_img(top_img=_pp, value=text_data["pos"], base="nc")
         detailed_images.append(pp_bg_2)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
-
-    #模特图
+    # 模特图
     def deal_pic_2_2(self):
         if self.get_text_value("模特图"):
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("模特图"),resize=1600)
         else:
             return
-    #场景图
+    # 场景图
     def deal_pic_2_3(self):
         if self.get_text_value("场景图"):
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("场景图"),resize=1600)
         else:
             return
 
-
-
     # 细节展示
     def deal_pic_3(self):
         detailed_images = []
@@ -334,6 +340,9 @@ class DetailPicGet(DetailBase):
                 if view_name == "后跟":
                     pp_jpg = pp_jpg.resize(value=500)
                     pp_png = pp_png.resize(value=500)
+                    if pp_jpg.height > 382:
+                        pp_png = pp_png.resize(value=330, base="high")
+                        pp_jpg = pp_jpg.resize(value=330, base="high")
                     pp_jpg, pp_png = self.copy_view(pp_jpg, pp_png)
                     resize_value = 469
                     value = (1243, 681)

+ 46 - 24
python/custom_plugins/plugins/detail_template/huilima/detail_huilima4.py

@@ -80,11 +80,25 @@ class DetailPicGet(DetailBase):
         pp_bg_1 = PictureProcessing(r"{}\1.jpg".format(self.root))
         font_1 = ImageFont.truetype(r"resources\ttf\puhui\Medium.ttf", 120)
         text_list = [
-            {"text": "标题", "pos": (89, 224)},
-            {"text": "副标题", "pos": (89, 345)},
+            {
+                "text": "标题",
+                "default": self.get_text_value("商品标题"),
+                "pos": (89, 224),
+                "max": 6,
+            },
+            {
+                "text": "副标题",
+                "default": "百搭舒适,型走随心",
+                "pos": (89, 345),
+                "max": 0,
+            },
         ]
         for text_data in text_list:
             text = self.get_text_value(text_data["text"])
+            if not text:
+                text = text_data["default"]
+                if text_data["max"] > 0 and text:
+                    text = text[:text_data["max"]]
             if text:
                 _pp = PictureProcessing().get_text_image_advanced(
                     font=font_1,
@@ -92,7 +106,7 @@ class DetailPicGet(DetailBase):
                     fill=(0, 0, 0),
                     return_mode="min_image",
                 )
-                pp_bg_1 = pp_bg_1.paste_img(top_img=_pp, value=text_data["pos"], base="nw")
+            pp_bg_1 = pp_bg_1.paste_img(top_img=_pp, value=text_data["pos"], base="nw")
         detailed_images.append(pp_bg_1)
 
         # 粘贴组合图
@@ -133,17 +147,35 @@ class DetailPicGet(DetailBase):
         detailed_images.append(pp_jpg)
         # 粘贴基础信息
         pp_bg_2 = PictureProcessing(r"{}\5.jpg".format(self.root))
-        font_1 = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 62)
+        font_1 = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 30)
         text_list = [
-            {"text": "鞋面材质", "pos": (767, 176)},
-            {"text": "内里材质", "pos": (1213, 176)},
-            {"text": "鞋底材质", "pos": (767, 345)},
-            {"text": "鞋垫材质", "pos": (1213, 345)},
-            {"text": "跟高", "pos": (767, 616)},
-            {"text": "前底厚度", "pos": (1196, 616)},
+            {
+                "text": "鞋面材质",
+                "default": self.get_text_value("商品面料"),
+                "pos": (767, 176),
+            },
+            {
+                "text": "内里材质",
+                "default": self.get_text_value("商品内里"),
+                "pos": (1213, 176),
+            },
+            {
+                "text": "鞋底材质",
+                "default": self.get_text_value("商品鞋底"),
+                "pos": (767, 345),
+            },
+            {
+                "text": "鞋垫材质",
+                "default": self.get_text_value("鞋垫"),
+                "pos": (1213, 345),
+            },
+            {"text": "跟高", "default": "6CM", "pos": (767, 616)},
+            {"text": "前底厚度", "default": "3CM", "pos": (1196, 616)},
         ]
         for text_data in text_list:
             text = self.get_text_value(text_data["text"])
+            if not text:
+                text = text_data["default"]
             if text:
                 _pp = PictureProcessing().get_text_image_advanced(
                     font=font_1,
@@ -192,29 +224,19 @@ class DetailPicGet(DetailBase):
         detailed_images.append(all_color_pp)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
-
-    #模特图
+    # 模特图
     def deal_pic_3_2(self):
         if self.get_text_value("模特图"):
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("模特图"),resize=1600)
         else:
             return
-    #场景图
+    # 场景图
     def deal_pic_3_3(self):
         if self.get_text_value("场景图"):
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("场景图"),resize=1600)
         else:
             return
 
-
     # 展示细节图
     def deal_pic_4(self):
         detailed_images = []

+ 69 - 42
python/custom_plugins/plugins/detail_template/huilima/detail_huilima5.py

@@ -109,6 +109,8 @@ class DetailPicGet(DetailBase):
         font_sub = ImageFont.truetype(r"resources\ttf\puhui\Medium.ttf", 50)
         main_text = self.get_text_value("标题")
         sub_text = self.get_text_value("副标题")
+        if not main_text:
+            main_text = "复古勃肯"
         _pp = PictureProcessing().get_text_image_advanced(
             font=font_main,
             text=main_text,
@@ -116,6 +118,8 @@ class DetailPicGet(DetailBase):
             spacing=20,
             return_mode="min_image",
         )
+        if not sub_text:
+            sub_text = "百搭|舒适|柔软|耐穿|复古|高级"
         _pp_sub = PictureProcessing().get_text_image_advanced(
             font=font_sub,
             text=sub_text,
@@ -176,6 +180,10 @@ class DetailPicGet(DetailBase):
         font_desc = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 48)
         text = self.get_text_value("设计理念-标题")
         text_desc = self.get_text_value("设计理念")
+        if not text:
+            text = "让勃肯鞋陪你CITY一下"
+        if not text_desc:
+            text_desc = "以独特得复古风格,让你在繁华都市中独树一帜\n独特得软木颗粒中底设计,提供出色得缓效果\n轻松打造出慵懒而不失格调的复古风\n后跟部分可灵活调整,让你在不同场合都能找到\n最舒适得穿着方式"
         _pp = PictureProcessing().get_text_image_advanced(
             font=font_1,
             text=text,
@@ -239,37 +247,53 @@ class DetailPicGet(DetailBase):
         pp_bg.paste_img(top_img=all_color_pp, base="cc", value=(0, -100))
         font_category = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 50)
         text_xiemian = self.get_text_value("鞋面")
+        if not text_xiemian:
+            text_xiemian = self.get_text_value("商品面料")
         text_xiedi = self.get_text_value("鞋底")
+        if not text_xiedi:
+            text_xiedi = self.get_text_value("商品鞋底")
         text_neili = self.get_text_value("内里")
+        if not text_neili:
+            text_neili = self.get_text_value("商品内里")
         text_xiedian = self.get_text_value("鞋垫")
-        pp_text_xiemian = PictureProcessing().get_text_image_advanced(
-            font=font_category,
-            text=text_xiemian,
-            fill=(0, 0, 0),
-            return_mode="min_image",
-        )
-        pp_text_xiedian = PictureProcessing().get_text_image_advanced(
-            font=font_category,
-            text=text_xiedian,
-            fill=(0, 0, 0),
-            return_mode="min_image",
-        )
-        pp_text_xiedi = PictureProcessing().get_text_image_advanced(
-            font=font_category,
-            text=text_xiedi,
-            fill=(0, 0, 0),
-            return_mode="min_image",
-        )
-        pp_text_neili = PictureProcessing().get_text_image_advanced(
-            font=font_category,
-            text=text_neili,
-            fill=(0, 0, 0),
-            return_mode="min_image",
-        )
-        pp_bg = pp_bg.paste_img(top_img=pp_text_xiemian, value=(416, 960), base="nw")
-        pp_bg = pp_bg.paste_img(top_img=pp_text_xiedian, value=(416, 1144), base="nw")
-        pp_bg = pp_bg.paste_img(top_img=pp_text_neili, value=(1157, 960), base="nw")
-        pp_bg = pp_bg.paste_img(top_img=pp_text_xiedi, value=(1157, 1144), base="nw")
+        if text_xiemian:
+            pp_text_xiemian = PictureProcessing().get_text_image_advanced(
+                font=font_category,
+                text=text_xiemian,
+                fill=(0, 0, 0),
+                return_mode="min_image",
+            )
+            pp_bg = pp_bg.paste_img(
+                top_img=pp_text_xiemian, value=(416, 960), base="nw"
+            )
+        if text_xiedian:
+            pp_text_xiedian = PictureProcessing().get_text_image_advanced(
+                font=font_category,
+                text=text_xiedian,
+                fill=(0, 0, 0),
+                return_mode="min_image",
+            )
+            pp_bg = pp_bg.paste_img(
+                top_img=pp_text_xiedian, value=(416, 1144), base="nw"
+            )
+        if text_xiedi:
+            pp_text_xiedi = PictureProcessing().get_text_image_advanced(
+                font=font_category,
+                text=text_xiedi,
+                fill=(0, 0, 0),
+                return_mode="min_image",
+            )
+            pp_bg = pp_bg.paste_img(
+                top_img=pp_text_xiedi, value=(1157, 1144), base="nw"
+            )
+        if text_neili:
+            pp_text_neili = PictureProcessing().get_text_image_advanced(
+                font=font_category,
+                text=text_neili,
+                fill=(0, 0, 0),
+                return_mode="min_image",
+            )
+            pp_bg = pp_bg.paste_img(top_img=pp_text_neili, value=(1157, 960), base="nw")
         detailed_images.append(pp_bg)
         return PictureProcessing(im=self.add_pic(detailed_images))
 
@@ -281,7 +305,11 @@ class DetailPicGet(DetailBase):
         font_title = ImageFont.truetype(r"resources\ttf\puhui\Bold.ttf", 150)
         font_sub = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 50)
         text_title = self.get_text_value("细节标题-1")
+        if not text_title:
+            text_title = "可调节饰扣"
         text_sub_title = self.get_text_value("细节副标题-1")
+        if not text_sub_title:
+            text_sub_title = "三孔调节饰扣,搭配不同脚型"
         pp_text_title = PictureProcessing().get_text_image_advanced(
             font=font_title,
             text=text_title,
@@ -317,7 +345,11 @@ class DetailPicGet(DetailBase):
         font_title = ImageFont.truetype(r"resources\ttf\puhui\Bold.ttf", 150)
         font_sub = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 50)
         text_title = self.get_text_value("细节标题-2")
+        if not text_title:
+            text_title = "细腻反绒鞋面"
         text_sub_title = self.get_text_value("细节副标题-2")
+        if not text_sub_title:
+            text_sub_title = "鞋面采用触感舒适得牛反绒\n彰显复古慵懒属性\n轻松驾驭不同穿搭"
         pp_text_title = PictureProcessing().get_text_image_advanced(
             font=font_title,
             text=text_title,
@@ -353,7 +385,11 @@ class DetailPicGet(DetailBase):
         font_title = ImageFont.truetype(r"resources\ttf\puhui\Bold.ttf", 150)
         font_sub = ImageFont.truetype(r"resources\ttf\puhui\Regular.ttf", 50)
         text_title = self.get_text_value("细节标题-3")
+        if not text_title:
+            text_title = "后跟下踩设计"
         text_sub_title = self.get_text_value("细节副标题-3")
+        if not text_sub_title:
+            text_sub_title = "单鞋&拖鞋 随时切换"
         pp_text_title = PictureProcessing().get_text_image_advanced(
             font=font_title,
             text=text_title,
@@ -381,29 +417,20 @@ class DetailPicGet(DetailBase):
 
         return PictureProcessing(im=self.add_pic(detailed_images))
 
-
-    #模特图
+    # 模特图
     def deal_pic_6_2(self):
         if self.get_text_value("模特图"):
-            mote_img = PictureProcessing(self.get_text_value("模特图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("模特图"),resize=1600)
         else:
             return
-    #场景图
+
+    # 场景图
     def deal_pic_6_3(self):
         if self.get_text_value("场景图"):
-            mote_img = PictureProcessing(self.get_text_value("场景图"))
-            mote_img = mote_img.resize(value=1600)
-            bg_img = PictureProcessing("RGB", (mote_img.width, mote_img.height), (255,255,255))
-            bg_img = bg_img.paste_img(top_img=mote_img,base="nc", value=(0, 0))
-            return bg_img
+            return self.concatAigcImage(self.get_text_value("场景图"),resize=1600)
         else:
             return
 
-
     # 场景图--产品展示
     def deal_pic_7(self):
         detailed_images = []

+ 154 - 148
python/custom_plugins/plugins_mode/detail_generate_base.py

@@ -19,8 +19,8 @@ from natsort import ns, natsorted
 import threading
 from concurrent.futures import ThreadPoolExecutor
 from concurrent.futures import TimeoutError as THTimeoutError
-
-
+from middleware import UnicornException
+from logger import logger
 # import math
 from PIL import ImageFont
 import settings
@@ -50,28 +50,29 @@ def _init_message_thread():
 _init_message_thread()
 
 
-def sendMessageAsync(code=0, msg="开始处理详情", data=None, msg_type="detail_progress"):
-    """异步发送消息"""
-
-    def _send_in_thread():
-        # 在消息线程中调度任务
-        future = asyncio.run_coroutine_threadsafe(
-            sendSocketMessage(
-                code=code,
-                msg=msg,
-                data=data,
-                msg_type=msg_type,
-            ),
-            _message_loop,
-        )
-        # 可选:等待结果或设置超时
-        try:
-            result = future.result(timeout=5.0)
-        except THTimeoutError:
-            print("消息发送超时")
-
-    # 在线程中执行异步任务的调度
-    _send_in_thread()
+# def sendMessageAsync(code=0, msg="开始处理详情", data=None, msg_type="detail_progress",progress=None):
+#     """异步发送消息"""
+#     if progress is None:
+#         data["progress"] = progress
+#     def _send_in_thread():
+#         # 在消息线程中调度任务
+#         future = asyncio.run_coroutine_threadsafe(
+#             sendSocketMessage(
+#                 code=code,
+#                 msg=msg,
+#                 data=data,
+#                 msg_type=msg_type,
+#             ),
+#             _message_loop,
+#         )
+#         # 可选:等待结果或设置超时
+#         try:
+#             result = future.result(timeout=5.0)
+#         except THTimeoutError:
+#             print("消息发送超时")
+
+#     # 在线程中执行异步任务的调度
+#     _send_in_thread()
 
 
 class DetailBase(object):
@@ -144,30 +145,45 @@ class DetailBase(object):
             return False
 
     def del_detail_folder(self):
-        out_path = "{out_put_dir}/{goods_no}".format(
-            out_put_dir=self.out_put_dir, goods_no=self.goods_no
+        out_path = "{out_put_dir}/切片图-{template_name}".format(
+            out_put_dir=self.out_put_dir,template_name=self.template_name
+        )
+        detail_image_path = "{out_put_dir}/详情页-{template_name}".format(
+            out_put_dir=self.out_put_dir,template_name=self.template_name
         )
         if not os.path.exists(out_path):
             return
         try:
-            shutil.rmtree(out_path)
+            shutil.rmtree(out_path,onerror=settings.handle_remove_readonly)
         except BaseException as e:
             print("删除文件夹失败", e)
+    def del_detail_longimage(self):
+        detail_image_path = "{out_put_dir}/详情页-{template_name}".format(
+            out_put_dir=self.out_put_dir,template_name=self.template_name
+        )
+        if not os.path.exists(detail_image_path):
+            return
+        try:
+            shutil.rmtree(detail_image_path)
+        except BaseException as e:
+            print("删除详情页失败", e)
+            logger.info(f"detail_generae_base 抠图前目录删除出现问题:{str(e)}")
 
     def run_all(self):
         if self.template_name:
-            self.out_put_dir = "{}/详情模板{}".format(
-                self.out_put_dir, self.template_name
+            self.out_put_dir = "{}/详情图-{}".format(
+                self.out_put_dir, self.goods_no
             )
 
         print("===================detailed_images=================")
         # 如果没有指定页面,则删除指定目录下的对应的详情文件夹
         if not self.assigned_page_list:
             self.del_detail_folder()
+            self.del_detail_longimage()
         detailed_images = self.deal_details()
         self.create_folder(self.out_put_dir)
-        detail_path = "{out_put_dir}/{goods_no}/详情页切片".format(
-            out_put_dir=self.out_put_dir, goods_no=self.goods_no
+        detail_path = "{out_put_dir}/切片图-{template_name}".format(
+            out_put_dir=self.out_put_dir, goods_no=self.goods_no,template_name=self.template_name
         )
         self.create_folder(detail_path)
         self.save_to_png(detailed_images=detailed_images, detail_path=detail_path)
@@ -188,57 +204,40 @@ class DetailBase(object):
             else:
                 if "主图" in self.assigned_page_list:
                     self.deal_all_main_pic()
-        # ----------如果是红蜻蜓则创建同颜色下的其他货号颜色文件夹---------------
-        if settings.PROJECT == "红蜻蜓":
-            if "data_all_goods_art_info" in self.goods_no_value:
-                # 数据格式:[{'number': '14250232', 'goods_art_no': 'AC52001173', 'color': '杏色'}, ]
-                for pic_data in self.goods_no_value["货号资料"]:
-                    if "颜色名称" not in pic_data:
-                        continue
-                    color_name = pic_data["颜色名称"]
-
-                    color_file_path = "{out_put_dir}/{goods_no}/{goods_number}".format(
-                        out_put_dir=self.out_put_dir,
-                        goods_no=self.goods_no,
-                        goods_number=pic_data["编号"],
-                    )
-                    for i in self.goods_no_value["data_all_goods_art_info"]:
-                        if color_name in i["color"]:
-                            new_path = "{out_put_dir}/{goods_no}/{goods_number}".format(
-                                out_put_dir=self.out_put_dir,
-                                goods_no=self.goods_no,
-                                goods_number="NUM{}".format(i["number"]),
-                            )
-                            if not os.path.exists(new_path):
-                                # 创建文件夹
-                                os.makedirs(new_path)
-                                self.move_one_pic(
-                                    color_file_path,
-                                    new_path,
-                                    "NUM{}".format(i["number"]),
-                                )
-        sendMessageAsync(
-            code=0,
-            msg="详情页生成完成",
-            msg_type="detail_progress",
-            data={
-                "goods_no": self.goods_no,
-                "temp_name": self.template_name,
-                "status": "已完成",
-                "goods_art_nos": self.goods_art_nos,
-            },
-        )
-        scp_path = "{out_put_dir}/{goods_no}".format(
-            out_put_dir=self.out_put_dir, goods_no=self.goods_no
+        scp_path = "{out_put_dir}".format(
+            out_put_dir=self.out_put_dir
         )
-        if self.get_text_value("模特图"):
-            model_pic = self.get_text_value("模特图")
-            shutil.copy(model_pic, f"{scp_path}/模特图.jpg")
-        if self.get_text_value("场景图"):
-            scene_pic = self.get_text_value("场景图")
-            shutil.copy(scene_pic, f"{scp_path}/场景图.jpg")
+        for pic_data in self.goods_no_value["货号资料"]:
+            scene_image = pic_data["场景图"]
+            model_image = pic_data["模特图"]
+            goods_art_no = pic_data["货号"]
+            # {out_put_dir}/{goods_number}
+            # 资料长度,决定是否添加货号后缀
+            goods_art_lens = len(self.goods_no_value["货号资料"])
+            concat_shuffix = "" if goods_art_lens == 1 else f"_{goods_art_no}"
+            if model_image:
+                self.copyImage(model_image, f"{scp_path}/模特图{concat_shuffix}.jpg")
+            if scene_image:
+                self.copyImage(scene_image, f"{scp_path}/场景图{concat_shuffix}.jpg")
         return True
-
+    def copyImage(self,src_path,limit_path):
+        try:
+          shutil.copy(src_path, limit_path)
+        except Exception as e:
+            logger.info(f"copyImage 复制模特图/场景图出错:{str(e)}",src_path,limit_path)
+    def concatAigcImage(self,image_path,resize=1600,bg_color=(255,255,255)):
+        """拼接模特图场景图"""
+        try:
+                mote_img = PictureProcessing(image_path)
+                mote_img = mote_img.resize(value=resize)
+                bg_img = PictureProcessing(
+                    "RGB", (mote_img.width, mote_img.height), bg_color
+                )
+                bg_img = bg_img.paste_img(top_img=mote_img, base="nc", value=(0, 0))
+                return bg_img
+        except Exception as e:
+             logger.info(f"copyImage 拼接模特图/场景图出错:{str(e)}")
+             return
     # 移动一张图片到新的文件夹
     def move_one_pic(self, old_path, new_path, new_name):
         image_file = os.listdir(old_path)[0]
@@ -249,46 +248,40 @@ class DetailBase(object):
 
     # 生成各个详情图切片
     def deal_details(self):
-        detailed_images = []
-        sendMessageAsync(
-            code=0,
-            msg="正在生成详情页切片",
-            msg_type="detail_progress",
-            data={
-                "goods_no": self.goods_no,
-                "temp_name": self.template_name,
-                "status": "进行中",
-                "goods_art_nos": self.goods_art_nos,
-            },
-        )
-        for index, func in enumerate(self.deal_pic_func_list):
-            image_pp = func()
-            if not self.assigned_page_list:
-                self.image_list_append(detailed_images, image_pp)
-            else:
-                index = "{}".format(index + 1)
-                if index in self.assigned_page_list:
+        try:
+            detailed_images = []
+            for index, func in enumerate(self.deal_pic_func_list):
+                image_pp = func()
+                if not self.assigned_page_list:
                     self.image_list_append(detailed_images, image_pp)
                 else:
-                    self.image_list_append(detailed_images, {"mes": "不生成"})
+                    index = "{}".format(index + 1)
+                    if index in self.assigned_page_list:
+                        self.image_list_append(detailed_images, image_pp)
+                    else:
+                        self.image_list_append(detailed_images, {"mes": "不生成"})
 
-        return [x for x in detailed_images if x]
+            return [x for x in detailed_images if x]
+        except KeyError as e:
+          raise UnicornException(f"缺少详情页资料:[{e}],请检查系统商品信息或excel是否缺少该字段")
+        except Exception as e:
+          raise UnicornException(str(e))
 
     # 生成拼接的图片
     def generate_spliced_picture(self):
-        sendMessageAsync(
-            code=0,
-            msg="正在生成详情拼接图",
-            msg_type="detail_progress",
-            data={
-                "goods_no": self.goods_no,
-                "temp_name": self.template_name,
-                "status": "进行中",
-                "goods_art_nos": self.goods_art_nos,
-            },
-        )
-        detail_path = "{out_put_dir}/{goods_no}/详情页切片".format(
-            out_put_dir=self.out_put_dir, goods_no=self.goods_no
+        # sendMessageAsync(
+        #     code=0,
+        #     msg="正在生成详情拼接图",
+        #     msg_type="detail_progress",
+        #     data={
+        #         "goods_no": self.goods_no,
+        #         "temp_name": self.template_name,
+        #         "status": "进行中",
+        #         "goods_art_nos": self.goods_art_nos,
+        #     },
+        # )
+        detail_path = "{out_put_dir}/切片图-{template_name}".format(
+            out_put_dir=self.out_put_dir, goods_no=self.goods_no,template_name=self.template_name
         )
         if not os.path.exists(detail_path):
             return
@@ -297,8 +290,8 @@ class DetailBase(object):
             detailed_images.append(PictureProcessing(image_data["file_path"]))
         # 生成拼接图
         img = self.add_pic(detailed_images)
-        join_path = "{out_put_dir}/{goods_no}/详情页".format(
-            out_put_dir=self.out_put_dir, goods_no=self.goods_no
+        join_path = "{out_put_dir}/详情页-{template_name}".format(
+            out_put_dir=self.out_put_dir, goods_no=self.goods_no,template_name=self.template_name
         )
         # self.create_folder(join_path)
         img.save("{}.jpg".format(join_path), format="JPEG")
@@ -360,32 +353,35 @@ class DetailBase(object):
             }
 
     def get_text_value(self, key, subsection_len=0):
-        text = ""
-        if key in self.goods_no_value:
-            if self.goods_no_value[key]:
-                text = str(self.goods_no_value[key])
-                text = text.replace(r"\n", "\n")
-
-        # if key in ["跟高", "鞋宽", "帮高", "脚掌围", "鞋长"]:
-        #     if text:
-        #         text = text.split(".")[0]
-
-        if subsection_len != 0:
-            text = text.split("\n")
-            text = [x for x in text if x]
-            if len(text) == 2:
-                text_1 = text[0]
-                text_2 = text[1]
-                return text_1, text_2
-            else:
-                if text:
+        try:
+            text = ""
+            if key in self.goods_no_value:
+                if self.goods_no_value[key]:
+                    text = str(self.goods_no_value[key])
+                    text = text.replace(r"\n", "\n")
+
+            # if key in ["跟高", "鞋宽", "帮高", "脚掌围", "鞋长"]:
+            #     if text:
+            #         text = text.split(".")[0]
+
+            if subsection_len != 0:
+                text = text.split("\n")
+                text = [x for x in text if x]
+                if len(text) == 2:
                     text_1 = text[0]
+                    text_2 = text[1]
+                    return text_1, text_2
                 else:
-                    text_1 = ""
-                text_2 = ""
-                return text_1, text_2
+                    if text:
+                        text_1 = text[0]
+                    else:
+                        text_1 = ""
+                    text_2 = ""
+                    return text_1, text_2
 
-        return text
+            return text
+        except:
+          raise UnicornException(f"缺少货号资料:[{key}],请检查系统商品信息或excel是否缺少该字段")
 
     def create_folder(self, path):
         if not os.path.exists(path):
@@ -597,6 +593,7 @@ class DetailBase(object):
     def move_other_pic(self, move_main_pic=True):
         # ------------------------------移动其他图片------------------------------
         goods_no_main_pic_number = 0
+        sorted_list_800 = []
         for goods_art_no_dict in self.goods_no_value["货号资料"]:
             if "800x800" not in goods_art_no_dict:
                 continue
@@ -611,10 +608,12 @@ class DetailBase(object):
                 goods_art_no = goods_art_no_dict["货号"]
             # print("goods_art_no:", goods_art_no)
             # 移动颜色图=====================
-            goods_art_no_f = "{}/{}".format(self.out_put_dir, self.goods_no)
+            # goods_art_no_f = "{}/{}".format(self.out_put_dir, self.goods_no)
+            sorted_list_800 = natsorted(goods_art_no_dict["800x800"], key=lambda x: x.split("(")[1].split(")")[0])
+            goods_art_no_f = "{}".format(self.out_put_dir)
             self.create_folder(goods_art_no_f)
             # 放入一张主图
-            old_pic_path_1 = goods_art_no_dict["800x800"][0]
+            old_pic_path_1 = sorted_list_800[0]
             shutil.copy(
                 old_pic_path_1,
                 "{}/颜色图{}{}".format(
@@ -624,18 +623,25 @@ class DetailBase(object):
 
             # 把其他主图放入作为款号图=====================
             if move_main_pic:
-                for pic_path in goods_art_no_dict["800x800"]:
-                    goods_no_main_pic_number += 1
+                for idx,pic_path in enumerate(sorted_list_800):
+                    index = idx + 1
+                    try:
+                      split_size = pic_path.split("_")[1].split(".")[0]
+                    except:
+                      split_size = ""
+                    suffix_name = "_"+split_size if split_size else ""
+                    print("pic_path=========>",split_size)
                     e = os.path.splitext(pic_path)[1]
                     shutil.copy(
                         pic_path,
-                        "{out_put_dir}/{goods_no}/主图{goods_no}({goods_no_main_pic_number}){e}".format(
+                        "{out_put_dir}/主图{goods_no}({goods_no_main_pic_number}){suffix_name}{e}".format(
                             out_put_dir=self.out_put_dir,
-                            goods_no=self.goods_no,
+                            goods_no=goods_art_no,
                             goods_no_main_pic_number=str(
-                                goods_no_main_pic_number + 10
-                            ).zfill(2),
+                                index
+                            ),
                             e=e,
+                            suffix_name=suffix_name
                         ),
                     )
 
@@ -669,7 +675,7 @@ class DetailBase(object):
 
         for _index, main_pic_path_list in enumerate(all_main_pic_path_list):
             self.check_state_end()
-            out_path_root = "{out_put_dir}/{goods_no}/main_image_{_index}".format(
+            out_path_root = "{out_put_dir}/main_image_{_index}".format(
                 out_put_dir=self.out_put_dir, goods_no=self.goods_no, _index=_index
             )
             check_path(out_path_root)

+ 69 - 6
python/databases.py

@@ -4,7 +4,7 @@ from typing import Dict
 from datetime import datetime
 from typing import Optional
 import json
-from sqlalchemy import and_, desc, asc
+from sqlalchemy import and_, desc, asc, delete
 from utils.utils_func import check_path
 from sqlalchemy.dialects import sqlite
 from model import DeviceConfig, PhotoRecord, SysConfigs, DeviceConfigTabs
@@ -16,11 +16,12 @@ sqlite_url = f"sqlite:///{sqlite_file_name}"
 engine = create_engine(
     sqlite_url,
     echo=False,
-    connect_args={"check_same_thread": False},  # 允许多线程访问
-    pool_size=10,
-    max_overflow=20,
-    pool_timeout=30,
-    pool_recycle=1800,
+    connect_args={"check_same_thread": False},
+    pool_size=20,        # 增加基础连接池大小
+    max_overflow=30,     # 增加最大溢出连接数
+    pool_timeout=60,     # 保持合理的超时时间
+    pool_recycle=1800,   # 连接回收时间(秒)
+    pool_pre_ping=True,  # 检查连接有效性
 )
 
 
@@ -51,6 +52,16 @@ class CRUD:
         session.refresh(db_obj)
         return db_obj
 
+    def truncate(self, session: Session):
+        """
+        使用SQL删除语句清空所有记录(更高效)
+        :param session: 数据库会话
+        """
+        stmt = delete(self.model)
+        result = session.exec(stmt)
+        session.commit()
+        return result.rowcount
+
     def read(
         self,
         session: Session,
@@ -170,6 +181,7 @@ class CRUD:
                 )
             )
         )
+        print("SQL 打印==>",str(query))
         result = session.exec(query).first()
         if result:
             for key, value in kwargs.items():
@@ -178,6 +190,32 @@ class CRUD:
             return result
         return None
 
+    def updateConditionsAll(self, session: Session, conditions: Dict, **kwargs):
+        """
+        根据条件更新记录
+        :param session: 数据库会话
+        :param conditions: 更新条件字典
+        :param kwargs: 需要更新的字段和值
+        :return: 更新后的对象
+        """
+        query = select(self.model).where(
+            and_(
+                *(
+                    getattr(self.model, key) == value
+                    for key, value in conditions.items()
+                )
+            )
+        )
+        print("SQL 打印==>", str(query))
+        results = session.exec(query).fetchall()
+        if results:
+            for obj in results:  # 遍历每个对象
+                for key, value in kwargs.items():
+                    setattr(obj, key, value)  # 对每个对象设置属性
+            session.commit()  # 提交事务以保存更改
+            return results
+        return None
+
 
 # 批量插入数据到设备配置表
 def batch_insert_device_configs(session: Session, action_tabs: list, data_list: list):
@@ -198,14 +236,39 @@ def batch_insert_device_configs(session: Session, action_tabs: list, data_list:
             session.add(device_config)
     session.commit()  # 合并事务提交
 
+
+def batch_insert_device_configsNew(
+    session: Session, action_tabs: list, data_list: list
+):
+    """批量插入数据到设备配置表"""
+    for idx, tab in enumerate(action_tabs):
+        crud = CRUD(DeviceConfigTabs)
+        device_tab = DeviceConfigTabs(
+            id=tab.get("id"),
+            mode_type=tab.get("mode_type"),
+            mode_name=tab.get("mode_name"),
+        )
+        create_obj = crud.create(session, obj_in=device_tab)
+    for data in data_list:
+        # data["tab_id"] = create_obj.id
+        # data["is_system"] = False
+        # if idx in [0, 6]:
+        #     data["is_system"] = True
+        device_config = DeviceConfig(**data)
+        session.add(device_config)
+    session.commit()  # 合并事务提交
+
+
 # 批量插入系统配置
 def batch_insert_sys_configs(session: Session, data_list: list):
     """批量插入数据到设备配置表"""
     for data in data_list:
+        print("data", data, type(data))
         config = SysConfigs(**data)
         session.add(config)
     session.commit()  # 合并事务提交
 
+
 # 插入照片记录
 async def insert_photo_records(
     image_deal_mode: int, goods_art_no: str, image_index: int, action_id: int

+ 43 - 23
python/detail_template_test.json

@@ -3,43 +3,63 @@
         "款号": "AQN191159",
         "货号资料": [
             {
-                "货号": "AQN1911592",
-                "文件夹名称": "AQN1911592",
+                "货号": "AC57000082",
+                "文件夹名称": "AC57000082",
                 "编号": "",
                 "颜色名称": "棕色",
                 "pics": {
-                    "俯视-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(1)_俯视_抠图.png",
-                    "俯视-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(1)_俯视_阴影.png",
-                    "侧视-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(2)_侧视_抠图.png",
-                    "侧视-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(2)_侧视_阴影.png",
-                    "后跟-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(3)_后跟_抠图.png",
-                    "后跟-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(3)_后跟_阴影.png",
-                    "鞋底-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(4)_鞋底_抠图.png",
-                    "鞋底-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(4)_鞋底_阴影.png",
-                    "内里-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(5)_内里_抠图.png",
-                    "内里-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(5)_内里_阴影.png",
-                    "其他1-抠图": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(6)_其他1_抠图.png",
-                    "其他1-阴影": "output/2025-09-01/AQN1911592/阴影图处理/AQN1911592(6)_其他1_阴影.png"
+                    "俯视-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(1)_俯视_抠图.png",
+                    "俯视-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(1)_俯视_阴影.png",
+                    "侧视-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(2)_侧视_抠图.png",
+                    "侧视-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(2)_侧视_阴影.png",
+                    "后跟-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(3)_后跟_抠图.png",
+                    "后跟-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(3)_后跟_阴影.png",
+                    "鞋底-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(4)_鞋底_抠图.png",
+                    "鞋底-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(4)_鞋底_阴影.png",
+                    "内里-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(5)_内里_抠图.png",
+                    "内里-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(5)_内里_阴影.png"
                 },
                 "800x800": [
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(1)_1600.png",
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(2)_1600.png",
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(3)_1600.png",
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(4)_1600.png",
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(5)_1600.png",
-                    "output/2025-09-01/AQN1911592/800x800/AQN1911592(6)_1600.png"
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(1)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(2)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(3)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(4)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(5)_320.png"
+                ]
+            },
+            {
+                "货号": "AC57000083",
+                "文件夹名称": "AC57000083",
+                "编号": "",
+                "颜色名称": "棕色",
+                "pics": {
+                    "俯视-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(1)_俯视_抠图.png",
+                    "俯视-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(1)_俯视_阴影.png",
+                    "侧视-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(2)_侧视_抠图.png",
+                    "侧视-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(2)_侧视_阴影.png",
+                    "后跟-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(3)_后跟_抠图.png",
+                    "后跟-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(3)_后跟_阴影.png",
+                    "鞋底-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(4)_鞋底_抠图.png",
+                    "鞋底-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(4)_鞋底_阴影.png",
+                    "内里-抠图": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(5)_内里_抠图.png",
+                    "内里-阴影": "output/2025-10-23/AC57000082/阴影图处理/AC57000082(5)_内里_阴影.png"
+                },
+                "800x800": [
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(1)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(2)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(3)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(4)_320.png",
+                    "output/2025-10-23/AC57000082/800x800/AC57000082(5)_320.png"
                 ]
             }
         ],
         "商品面料": "头层牛皮",
         "商品内里": "猪皮革",
-        "商品鞋底": "橡胶",
         "鞋垫": "猪皮革",
         "商品标题": "舒适休闲男豆豆鞋男单鞋",
         "商品价格": "132.00",
         "性别": "男性",
         "token": "Bearer 18323b96c68234597b1fa8d10fecb6bbe45cadc3",
-        "场景图": "output/2025-09-01/AQN1911592/场景 图.jpg",
-        "模特图": "output/2025-09-01/AQN1911592/模特图.jpg"
+         "场景图": "output/2025-10-23/AC57000082/场景图.jpg"
     }
 }

+ 2 - 2
python/detail_template_test.py

@@ -15,7 +15,7 @@ for goods_no, value in data.items():
     d = DetailPicGet(
         goods_no=goods_no,
         goods_no_value=value,
-        out_put_dir=r"C:\Development\project\python\CameraMachine\python\output\clothing2",
-        test=True,
+        out_put_dir=r"C:\Development\project\python\CameraMachine\python\output\detail_huilima1",
+        test=False,
     )
 print("生成成功")

+ 1 - 1
python/mcu/BaseClass.py

@@ -31,7 +31,7 @@ class BaseClass:
             loop.create_task(
                 self.websocket_manager.send_personal_message(data, self.websocket)
             )
-
+        print("\033[1;32;40m 发送消息===>sendSocketMessage \033[0m", data)
     async def asyncSendSocketMessage(self, code=0, msg="", data=None, device_status=2):
         data = {
             "code": code,

+ 3 - 3
python/mcu/BlueToothMode.py

@@ -64,9 +64,9 @@ class BlueToothMode(BaseClass, metaclass=SingletonType):
             devices = await BleakScanner.discover()
         except BaseException as e:
             self.print_error("蓝牙疑似未打开,{}".format(e))
-            self.sendSocketMessage(
-                code=0, msg="蓝牙疑似未打开,{}".format(e), data=None, device_status=-1
-            )
+            # self.sendSocketMessage(
+            #     code=0, msg="蓝牙疑似未打开,{}".format(e), data=None, device_status=-1
+            # )
             return
         for d in devices:
             # print(f"Device: {d.name} - Address: {d.address}")

+ 61 - 39
python/mcu/DeviceControl.py

@@ -47,6 +47,8 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         self.state_camera_steering = 3
         self.state_turntable_steering = 3
         self.state_overturn_steering = 3
+        # 是否实时获取mcu状态信息
+        self.is_get_mcu_state = True
         self.state_move_turntable_steering = 3
         self.last_from_mcu_move_respond_data = None
         self.camera_motor_speed = 0
@@ -192,6 +194,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         self.to_init_device_origin_point(device_name="mcu", is_force=is_force)
         print("MCU 开始循环~")
         logger.info("MCU 开始循环~")
+        loop = asyncio.get_event_loop()
         while 1:
             await asyncio.sleep(1)
             if not self.serial_ins or not self.connect_state:
@@ -204,7 +207,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                 #     device_status=2,
                 # )
                 # print("mcu   send_cmd")
-                self.send_cmd()
+                loop.create_task(self.send_cmd())
                 # time.sleep(0.01)
                 if not self.get_basic_info_mcu():
                     pass
@@ -414,30 +417,36 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         await asyncio.sleep(0.001)
         while True:
             if self.send_data_queue:
-                self.sendSocketMessage(msg="正在发送命令", device_status=1)
+                # self.sendSocketMessage(msg="正在发送命令", device_status=1)
                 data = self.send_data_queue.pop(0)
                 self.serial_ins.write_cmd(data)
-                self.sendSocketMessage(msg="命令发送完成", device_status=2)
+                # self.sendSocketMessage(msg="命令发送完成", device_status=2)
             else:
                 break
 
-    def send_cmd(self):
+    async def send_cmd(self):
         self.lock.acquire()
+        asyncio.sleep(0.01)
         if self.send_data_queue:
-            self.sendSocketMessage(msg="正在发送命令", device_status=1)
+            # self.sendSocketMessage(msg="正在发送命令", device_status=1)
             data = self.send_data_queue.pop(0)
             self.serial_ins.write_cmd(data)
-            self.sendSocketMessage(msg="命令发送完成", device_status=2)
-        # else:
-        #     self.t_n += 1
-        #     # 加大发送获取基础数据的时间间隔
-        #     # 默认为0.01秒一个循环,每隔1.5秒发送数据
-        #     if self.t_n > 150:
-        #         self.t_n = 0
-        #         data = [self.command["get_all_info"], 1]
-        #         self.serial_ins.write_cmd(data)
+            # self.sendSocketMessage(msg="命令发送完成", device_status=2)
+        else:
+            # self.t_n += 1
+            # 加大发送获取基础数据的时间间隔
+            # 默认为0.01秒一个循环,每隔1.5秒发送数据
+            if self.t_n == 150:
+                # self.t_n = 0
+                self.send_get_all_info_to_mcu()
         self.lock.release()
 
+    def send_get_all_info_to_mcu(self):
+        if self.is_get_mcu_state is False:
+            return
+        data = [self.command["get_all_info"], 1]
+        self.serial_ins.write_cmd(data)
+
     def print_mcu_error_data(self, receive_data):
         # 扫码数据
         try:
@@ -465,7 +474,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
 
         # self.self_sign.emit({"type": "connect_sign", "data": connect_flag})
         message = {"type": "connect_sign", "data": connect_flag}
-        self.sendSocketMessage(msg="接收接信息", data=message)
+        self.sendSocketMessage(msg="接收接信息", data=message)
         print("接收链接信息")
         logger.info("接收链接信息")
         return
@@ -539,6 +548,9 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         receive_data = self.serial_ins.read_cmd(out_time=1)
         if receive_data is False:
             print("------------------------------------------------4657564654")
+            print(
+                "------------------------------------------------get_basic_info_mcu------------------"
+            )
             logger.info("------------------------------------------------4657564654")
             self.connect_state = False
             return False
@@ -1224,35 +1236,41 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             self.init_state = False
             print("关闭MCU")
             logger.info("关闭MCU")
+
     def close_lineConnect(self):
-        ''''关闭有线遥控器连接'''
+        """'关闭有线遥控器连接"""
         self.line_control.port_name = ""
         self.line_control.close_connect()
         print("关闭有线遥控器")
         logger.info("关闭有线遥控器")
+
     @property
     def mcu_move_state(self):
-        if self.m_t == 1:
-            if (
-                self.state_camera_motor == 2
-                and self.state_camera_steering == 2
-                and self.state_turntable_steering == 2
-                and self.state_overturn_steering == 2
-            ):
-                self._mcu_move_state = 2
-            else:
-                self._mcu_move_state = 1
+        if self.is_get_mcu_state is False:
+            self._mcu_move_state = 2
+            # self.action_state = 2
         else:
-            if (
-                self.state_camera_motor == 2
-                and self.state_camera_steering == 2
-                and self.state_turntable_steering == 2
-                and self.state_overturn_steering == 2
-                and self.state_move_turntable_steering == 2
-            ):
-                self._mcu_move_state = 2
+            if self.m_t == 1:
+                if (
+                    self.state_camera_motor == 2
+                    and self.state_camera_steering == 2
+                    and self.state_turntable_steering == 2
+                    and self.state_overturn_steering == 2
+                ):
+                    self._mcu_move_state = 2
+                else:
+                    self._mcu_move_state = 1
             else:
-                self._mcu_move_state = 1
+                if (
+                    self.state_camera_motor == 2
+                    and self.state_camera_steering == 2
+                    and self.state_turntable_steering == 2
+                    and self.state_overturn_steering == 2
+                    and self.state_move_turntable_steering == 2
+                ):
+                    self._mcu_move_state = 2
+                else:
+                    self._mcu_move_state = 1
 
         # self._mcu_move_state = 2
         return self._mcu_move_state
@@ -1397,7 +1415,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         if self.connect_state:
             self.lock.acquire()
             # print('==========================>1111')
-            # print("-------------------to_get_mcu_base_info--------------------------")
+            print("-------------------to_get_mcu_base_info--------------------------")
             data = [self.command["get_all_info"], 1]
             f = True
             try:
@@ -1653,6 +1671,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             )
             self.msg_type = "mcu"
             await self.controlDevice("laser_position", 1)
+        self.action_state = 2
 
     async def run_mcu_config_single(
         self,
@@ -1686,11 +1705,13 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                 print("action异常终止")
                 logger.info("action异常终止")
                 return
-            self.msg_type = "run_mcu_single"
             program_item.smart_shooter = smart_shooter
             await program_item.run(3)
             self.msg_type = "mcu"
-            print("发送 run_mcu_signle消息","{} 执行完成~".format(program_item.action_name))
+            print(
+                "发送 run_mcu_signle消息",
+                "{} 执行完成~".format(program_item.action_name),
+            )
             self.sendSocketMessage(
                 code=0,
                 msg="{} 执行完成~".format(program_item.action_name),
@@ -1698,7 +1719,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                 device_status=2,
             )
             self.action_state = 2
-            self.msg_type = msg_type
+            self.msg_type = "run_mcu_single"
             print("发送 run_mcu_signle消息", "执行完成")
             self.sendSocketMessage(
                 code=0,
@@ -1710,6 +1731,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             self.sendSocketMessage(
                 code=1, msg="未查询到重拍记录得配置信息,请确认", device_status=0
             )
+        self.action_state = 2
 
     async def only_take_photo(self, goods_art_no, image_index, record_id):
         await asyncio.sleep(0.1)

+ 15 - 7
python/mcu/ProgramItem.py

@@ -150,8 +150,11 @@ class ProgramItem(BaseClass):
         last_num_1 = self.mcu.last_mcu_info_data["num"]
         await self.mcu.cleanAllReceiveData()
         while 1:
+            print("\033[1;31m执行检查动作\033[0m", self.mcu.mcu_move_state)
+            print("\033[1;31m执行检查动作\033[0m", self.mcu.action_state)
             if self.mcu.action_state != 1:
                 # 外部终止,停止运行
+                print("\033[1;31m执行结束\033[0m", "外部终止,停止运行")
                 return False
             cr_time = time.time()
             print(cr_time - _s, cr_time, _s)
@@ -160,20 +163,22 @@ class ProgramItem(BaseClass):
                 self.set_state(state_value=99)  # 标记异常
                 print("MCU检测运动未停止,自动退出")
                 self.sendSocketMessage(msg=self.error_info_text, device_status=-1)
+                print("\033[1;31m执行结束\033[0m", "MCU检测运动未停止,自动退出")
                 return False
                 # return True
             # 存在时间间隙,导致误认为所有设备已完成运动
             if self.mcu.mcu_move_state == 2:
+                print("\033[1;31m执行结束\033[0m", "导致误认为所有设备已完成运动")
                 return True
             else:
                 self.mcu.to_get_mcu_base_info()
-                await self.mcu.send_all_cmd()
+                asyncio.create_task(self.mcu.send_all_cmd())
                 await asyncio.sleep(0.5)
                 self.mcu.get_basic_info_mcu()
                 # return True
-
-            await asyncio.sleep(0.1)
-            # self.mcu.to_get_mcu_base_info()
+        print("\033[1;31m执行结束\033[0m", self.mcu.action_state)
+        # await asyncio.sleep(0.1)
+        # self.mcu.to_get_mcu_base_info()
 
     async def run(self, total_len=5, *args):
         if total_len == 1:
@@ -223,13 +228,16 @@ class ProgramItem(BaseClass):
                     device_name="turntable_steering", value=self.turntable_angle
                 )
                 time.sleep(0.1)
-            self.mcu.send_all_cmd()
+            loop = asyncio.get_event_loop()
+            # self.mcu.send_all_cmd()
+            loop.create_task(self.mcu.send_all_cmd())
 
     async def do_run(self, *args):
         await asyncio.sleep(0.001)
         # if not self.goods_art_no:  # and self.action_name != "初始化位置"
         #     return False
         start_time = time.time()
+        self.mcu.is_get_mcu_state = False
         # ============连接MCU 处理步进电机与舵机等
         if settings.IS_MCU:
             if self.mode_type != "其他配置" and await self.check_mcu_move_is_stop() is False:
@@ -273,14 +281,14 @@ class ProgramItem(BaseClass):
                 # time.sleep(0.1)
 
             # MCU运动是否有停止检查,设定超时时间
-            await self.mcu.send_all_cmd()
+            asyncio.create_task(self.mcu.send_all_cmd())
             if self.mode_type != "其他配置":
                 await asyncio.sleep(1.2)
                 print("二次检查")
                 if await self.check_mcu_move_is_stop(re_check=True) is False:
                     print("MCU检测运动未停止,自动退出,   提前退出")
                     return
-
+        self.mcu.is_get_mcu_state = True
         if self.delay_time:
             await asyncio.sleep(self.delay_time)
         if self.is_photograph:

+ 75 - 88
python/mcu/RemoteControlV2.py

@@ -234,105 +234,92 @@ class RemoteControlV2(BaseClass):
         self.msg_type = "blue_tooth"
         self.photo_take_state = 2
 
-    async def handlerTakePhoto(self, smart_shooter=None):
+    async def handlerTakePhoto(self, smart_shooter=None,session=None,record=None):
         """处理单独拍照"""
         await asyncio.sleep(0.1)
-        print("开始单拍0")
-        session = SqlQuery()
-        crud = CRUD(PhotoRecord)
-        record = crud.read(session=session, order_by="id", ascending=False)
-        print("开始单拍0-读取数据库")
-        if record == None:
-            # 发送失败消息
+        print("开始单拍1")
+        if record.image_index == 19:
+            self.msg_type = "photo_take"
             self.sendSocketMessage(
                 code=1,
-                msg="单拍失败,请先输入货号或扫码进行组合拍摄",
+                msg="单拍失败,单个货号最多允许拍摄20张产品图",
                 data=None,
                 device_status=2,
             )
+            self.msg_type = "blue_tooth"
+            return
+        deviceConfig = CRUD(DeviceConfig)
+        deviceConfigData = deviceConfig.read(session=session, conditions={"id": record.action_id})
+        select_tab_id = deviceConfigData.tab_id
+        AllTabConfig = deviceConfig.read_all(session=session, conditions={"tab_id": select_tab_id})
+        action_id = 0
+        if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
+            action_id = AllTabConfig[0].id
         else:
-            print("开始单拍1")
-            if record.image_index == 19:
-                self.msg_type = "photo_take"
-                self.sendSocketMessage(
-                    code=1,
-                    msg="单拍失败,单个货号最多允许拍摄20张产品图",
-                    data=None,
-                    device_status=2,
-                )
-                self.msg_type = "blue_tooth"
-                return
-            deviceConfig = CRUD(DeviceConfig)
-            deviceConfigData = deviceConfig.read(session=session, conditions={"id": record.action_id})
-            select_tab_id = deviceConfigData.tab_id
-            AllTabConfig = deviceConfig.read_all(session=session, conditions={"tab_id": select_tab_id})
-            action_id = 0
-            if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
-                action_id = AllTabConfig[0].id
-            else:
-                action_id = AllTabConfig[len(AllTabConfig) - 1].id
-            image_index = record.image_index + 1
-            self.photo_take_state = 1
-            deviceConfig = CRUD(DeviceConfig)
-            deviceConfigData = deviceConfig.read(
-                session=session, conditions={"id": record.action_id}
-            )
-            select_tab_id = deviceConfigData.tab_id
-            AllTabConfig = deviceConfig.read_all(
-                session=session, conditions={"tab_id": select_tab_id}
-            )
-            action_id = 0
-            if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
-                action_id = AllTabConfig[0].id
+            action_id = AllTabConfig[len(AllTabConfig) - 1].id
+        image_index = record.image_index + 1
+        self.photo_take_state = 1
+        deviceConfig = CRUD(DeviceConfig)
+        deviceConfigData = deviceConfig.read(
+            session=session, conditions={"id": record.action_id}
+        )
+        select_tab_id = deviceConfigData.tab_id
+        AllTabConfig = deviceConfig.read_all(
+            session=session, conditions={"tab_id": select_tab_id}
+        )
+        action_id = 0
+        if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
+            action_id = AllTabConfig[0].id
+        else:
+            action_id = AllTabConfig[len(AllTabConfig) - 1].id
+        image_index = record.image_index + 1
+        self.photo_take_state = 1
+        state, record_id = await insert_photo_records(
+            record.image_deal_mode,
+            record.goods_art_no,
+            image_index,
+            action_id,
+        )
+        session.close()
+        print("开始单拍1-插入数据")
+        try:
+            if smart_shooter == None:
+                capture_one = DigiCam()
+                watch_dog = FileEventHandler()
+                if watch_dog.observer is None:
+                    captrure_folder_path = capture_one.getCaptureFolderPath()
+                    watch_dog.start_observer(captrure_folder_path)
+                watch_dog.goods_art_no = record.goods_art_no
+                watch_dog.image_index = image_index
+                print("开始单拍1-检查相机")
+                capture_one.run_capture_action("Capture")
+                print("开始单拍1-完成拍照")
             else:
-                action_id = AllTabConfig[len(AllTabConfig) - 1].id
-            image_index = record.image_index + 1
-            self.photo_take_state = 1
-            state, record_id = await insert_photo_records(
-                record.image_deal_mode,
-                record.goods_art_no,
-                image_index,
-                action_id,
-            )
-            print("开始单拍1-插入数据")
-            try:
-                if smart_shooter == None:
-                    capture_one = DigiCam()
-                    watch_dog = FileEventHandler()
-                    if watch_dog.observer is None:
-                        captrure_folder_path = capture_one.getCaptureFolderPath()
-                        watch_dog.start_observer(captrure_folder_path)
-                    watch_dog.goods_art_no = record.goods_art_no
-                    watch_dog.image_index = image_index
-                    print("开始单拍1-检查相机")
-                    capture_one.run_capture_action("Capture")
-                    print("开始单拍1-完成拍照")
-                else:
-                    loop = asyncio.get_event_loop()
-                    loop.create_task(
-                        smart_shooter.CameraShooter(
-                            msg_type="handler_take_picture",
-                            goods_art_no=record.goods_art_no,
-                            id=record_id,
-                        ),
-                        name="CameraShooter",
-                    )
-                await asyncio.sleep(1)
-                self.msg_type = "photo_take"
-                self.sendSocketMessage(
-                    code=0,
-                    msg="{} 执行完成~".format(
-                        "执行右脚程序"
-                        if record.image_deal_mode == 1
-                        else "执行左脚程序"
+                loop = asyncio.get_event_loop()
+                loop.create_task(
+                    smart_shooter.CameraShooter(
+                        msg_type="handler_take_picture",
+                        goods_art_no=record.goods_art_no,
+                        id=record_id,
                     ),
-                    data={"goods_art_no": record.goods_art_no, "id": record_id},
-                    device_status=2,
+                    name="CameraShooter",
                 )
-                self.msg_type = "blue_tooth"
-            except Exception as e:
-                print(f"错误:{e}")
-                self.sendSocketMessage(1, "处理失败,请重试", device_status=-1)
+            await asyncio.sleep(1)
+            self.msg_type = "photo_take"
+            self.sendSocketMessage(
+                code=0,
+                msg="{} 执行完成~".format(
+                    "执行右脚程序"
+                    if record.image_deal_mode == 1
+                    else "执行左脚程序"
+                ),
+                data={"goods_art_no": record.goods_art_no, "id": record_id},
+                device_status=2,
+            )
+            self.msg_type = "blue_tooth"
+        except Exception as e:
+            print(f"错误:{e}")
+            self.sendSocketMessage(1, "处理失败,请重试", device_status=-1)
         self.photo_take_state = 0
 
     async def analysis_received_data(self):

+ 39 - 29
python/mcu/capture/smart_shooter_class.py

@@ -235,8 +235,8 @@ class SmartShooter(metaclass=SingletonType):
         camera_states, _ = await self.GetCameraInfo(is_send=False)
         if not camera_states:
             return False, "请先连接相机"
+        socket, context = self.__create_req()
         try:
-            socket, context = self.__create_req()
             req = {}
             req["msg_type"] = "Request"
             req["msg_id"] = "LiveviewFPS"
@@ -260,8 +260,8 @@ class SmartShooter(metaclass=SingletonType):
         camera_states, _ = await self.GetCameraInfo(is_send=False)
         if not camera_states:
             return False, "请先连接相机"
+        socket, context = self.__create_req()
         try:
-            socket, context = self.__create_req()
             req = {}
             req["msg_type"] = "Request"
             req["msg_id"] = "SetProperty"
@@ -282,7 +282,16 @@ class SmartShooter(metaclass=SingletonType):
             context.term()
             msg_send = "相机未连接或软件未打开"
             return False, msg_send
-
+    async def getConfigIso(self):
+            """获取ISO配置信息"""
+            camera_configs = settings.getSysConfigs(
+                "camera_configs",
+                "iso_config",
+                {"low": 100, "high": 6400, "mode": "un_auto"},
+            )
+            low_iso = camera_configs.get("low", 100)
+            high_iso = camera_configs.get("high", 6400)
+            return low_iso, high_iso
     async def EnableCameraPreview(self, enable_status=True, msg_type=""):
         self.msg_type = msg_type
         await self.SetCameraFPS(5)
@@ -293,13 +302,7 @@ class SmartShooter(metaclass=SingletonType):
         if not camera_states:
             return False, "请先连接相机"
         try:
-            camera_configs = settings.getSysConfigs(
-                "camera_configs",
-                "iso_config",
-                {"low": 100, "high": 6400, "mode": "un_auto"},
-            )
-            low_iso = camera_configs.get("low", 100)
-            high_iso = camera_configs.get("high", 6400)
+            low_iso,high_iso = await self.getConfigIso()
             print("LOW_ISO", low_iso)
             print("HIGH_ISO", high_iso)
             # 等于auto就不设置
@@ -325,11 +328,11 @@ class SmartShooter(metaclass=SingletonType):
             if not msg_result:
                 self.perview_state = False
                 msg_send = "预览启用失败"
-                self.sendSocketMessage(
-                    code=0,
-                    msg=msg_send,
-                    device_status=2,
-                )
+                # self.sendSocketMessage(
+                #     code=0,
+                #     msg=msg_send,
+                #     device_status=2,
+                # )
                 return False, "预览启用失败"
             msg_send = "预览启用成功" if enable_status else "预览关闭成功"
             message = {
@@ -366,8 +369,8 @@ class SmartShooter(metaclass=SingletonType):
         print("CameraAutofocus 执行对焦")
         if not camera_states:
             return False, "请先连接相机"
+        socket, context = self.__create_req()
         try:
-            socket, context = self.__create_req()
             req = {}
             req["msg_type"] = "Request"
             req["msg_id"] = "Autofocus"
@@ -377,17 +380,17 @@ class SmartShooter(metaclass=SingletonType):
             print("json_msg", json_msg)
             msg_result = json_msg.get("msg_result")
             if not msg_result:
-                msg_send = "对焦失败"
-                message = {
-                    "code": 1,
-                    "msg": msg_send,
-                    "data": None,
-                    "msg_type": "smart_shooter_photo_take",
-                    "device_status": -1,
-                }
-                await self.websocket_manager.send_personal_message(
-                    message, self.websocket
-                )
+                # msg_send = "对焦失败"
+                # message = {
+                #     "code": 1,
+                #     "msg": msg_send,
+                #     "data": None,
+                #     "msg_type": "smart_shooter_photo_take",
+                #     "device_status": -1,
+                # }
+                # await self.websocket_manager.send_personal_message(
+                #     message, self.websocket
+                # )
                 return False, "对焦失败"
             return True, "对焦成功"
         except zmq.Again:
@@ -414,8 +417,15 @@ class SmartShooter(metaclass=SingletonType):
         print("camera_states CameraShooter", camera_states)
         if not camera_states:
             return False, "请先连接相机"
+        socket, context = self.__create_req()
         try:
-            socket, context = self.__create_req()
+            low_iso,high_iso = await self.getConfigIso()
+            print("LOW_ISO", low_iso)
+            print("HIGH_ISO", high_iso)
+            if str(low_iso).lower() != "auto":
+                    await self.setCameraProperty(property="ISO", value=str(low_iso))
+            else:
+                    print("low_iso 等于auto就不设置")
             req = {}
             req["msg_type"] = "Request"
             req["msg_id"] = "Shoot"
@@ -556,7 +566,7 @@ class SmartShooter(metaclass=SingletonType):
                 asyncio.run(self.callback_listen(json_msg))
             except zmq.Again:
                 print("接收超时,继续监听...")
-                logger.info("接收超时,继续监听...")
+                # logger.info("接收超时,继续监听...")
                 continue
             except Exception as e:
                 self.connect_status = False

+ 8 - 0
python/models.py

@@ -98,6 +98,7 @@ class HandlerDetail(BaseModel):
     temp_list: list[TemplateItem] = Field(default=[], description="所有模板列表")
     logo_path: Optional[str] = Field(default="", description="logo地址路径")
     is_only_cutout: Optional[int] = Field(default=0, description="是否仅抠图;0否;1是")
+    is_check: Optional[int] = Field(default=0, description="是否仅检测;0否;1是")
     online_stores: Optional[list[str]] = Field(
         default=[], description="上传的店铺,数组形式"
     )
@@ -138,3 +139,10 @@ class RecordUpdate(BaseModel):
 
     id: int = Field(default=0, description="记录id")
     image_path: str = Field(default=None, description="图片地址")
+
+
+class SyncLocalConfigs(BaseModel):
+    """同步系统配置"""
+
+    token: str = Field(default=None, description="用户token")
+    

+ 1 - 1
python/service/auto_deal_pics/base_deal.py

@@ -909,7 +909,7 @@ class BaseDealImage(object):
         total_num = len(original_photo_list)
         # 当天日期作为文件夹
         seconds = time.time()
-        output_path = "output/{f_name}".format(f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
+        output_path = "{output}/{f_name}".format(output=settings.OUTPUT_DIR,f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
 
         # 遍历每个匹配好的数据进行处理
         n = 0

+ 10 - 7
python/service/base.py

@@ -8,7 +8,7 @@ import shutil
 from hashlib import sha256, md5
 import requests
 from datetime import datetime
-
+from settings import OUTPUT_DIR,handle_remove_readonly
 
 # 获取digicam的路径
 def check_install_path(other):
@@ -174,7 +174,7 @@ def get_image_mask(path):
 # 删除文件夹下的所有文件
 def remove_all_file(directory):
     try:
-        shutil.rmtree(directory)
+        shutil.rmtree(directory,onerror=handle_remove_readonly)
         os.makedirs(directory)
     except Exception as e:
         print(f'Failed to clear directory {directory}. Reason: {e}')
@@ -240,16 +240,19 @@ def check_move_goods_art_no_folder(path, goods_art_nos,limit_folder):
         for folder_data in temp_folder_list:
             # folder_path = folder_data["folder_path"]
             folder_name = folder_data["folder_name"]
-            _p = "output/{}/{}/原始图".format(folder_name, goods_art_no)
+            _p = "{}/{}/{}/原始图".format(OUTPUT_DIR,folder_name, goods_art_no)
             if os.path.exists(_p):
-                folder_data["folder_path"] = f"output/{folder_name}/{goods_art_no}"
+                folder_data["folder_path"] = f"{OUTPUT_DIR}/{folder_name}/{goods_art_no}"
                 # 整个目录移动到目标目录
                 folder_list[goods_art_no] = folder_data
                 if not os.path.exists(f"{limit_folder}/{goods_art_no}"):
                     # 目标不存在
-                    folder_list[goods_art_no] = folder_data
-                    print("移动目录", folder_data["folder_path"], limit_folder)
-                    shutil.move(folder_data["folder_path"], limit_folder)
+                    try:
+                        shutil.move(folder_data["folder_path"], limit_folder)
+                        folder_list[goods_art_no] = folder_data
+                        print("移动目录", folder_data["folder_path"], limit_folder)
+                    except:
+                        continue
                 else:
                     # 如果希望覆盖
                     print(f"目标目录 {limit_folder}/{goods_art_no} 已存在,跳过移动")

+ 82 - 46
python/service/base_deal.py

@@ -23,9 +23,8 @@ import requests
 import copy, asyncio
 from settings import sendSocketMessage
 from utils.common import message_queue
-
-
-def sendAsyncMessage(msg="", goods_arts=[], status=""):
+from logger import logger
+def sendAsyncMessage(msg="", goods_arts=[], status="",progress={}):
     """异步发送消息"""
     data = {
         "code": 0,
@@ -35,6 +34,15 @@ def sendAsyncMessage(msg="", goods_arts=[], status=""):
             "status": status,
             "goods_art_nos": goods_arts,
         },
+        "progress":{
+                "msg_type":"segment_progress",
+                "name":"抠图",
+                "goods_art_no":progress.get("goods_art_no",""),
+                "status":progress.get("status"),
+                "current":progress.get("current",0),
+                "total":progress.get("total",0),
+                "error":progress.get("error",0)
+            },
         "msg_type": "segment_progress",
     }
     message_queue.put_nowait(data)
@@ -329,14 +337,22 @@ class BaseDealImage(object):
         is_image_deal_mode = 0
 
         # 删除目录再新建
-        if os.path.exists("{}/阴影图处理".format(folder_path)):
-            shutil.rmtree("{}/阴影图处理".format(folder_path))
+        try:
+          if os.path.exists("{}/阴影图处理".format(folder_path)):
+            shutil.rmtree("{}/阴影图处理".format(folder_path),onerror=settings.handle_remove_readonly)
+        except Exception as e:
+          print('An exception occurred')
+          logger.info(f"base deal 抠图前目录删除出现问题:{str(e)}")
 
         self.crate_all_folders(folder_path)
         print(
             "***************all_original_images*********************",
             all_original_images,
         )
+        is_flip_800image = settings.getSysConfigs(
+            "basic_configs", "is_flip_800image", 1
+        )
+        image_deal_mode = int(is_flip_800image)
         for image_dict in all_original_images:
             if windows:
                 if windows.state != 1:
@@ -360,13 +376,14 @@ class BaseDealImage(object):
                 f"*****************此处判断鞋子是否为左右脚====>{image_index}<======={is_image_deal_mode}=======>**********************"
             )
             # 此处判断鞋子是否为左右脚
-            if image_index == 1:
-                is_image_deal_mode = 0
-                print("开始识别左右脚=========>")
-                if OnePicDeal(self.token).check_shoe_is_right(
-                    image_path=original_move_bg_image_path
-                ):
-                    is_image_deal_mode = 1  # 1表示要镜像,0表示不做镜像
+            if image_deal_mode == 1:
+                if image_index == 1:
+                    is_image_deal_mode = 0
+                    print("开始识别左右脚=========>")
+                    if OnePicDeal(self.token).check_shoe_is_right(
+                        image_path=original_move_bg_image_path
+                    ):
+                        is_image_deal_mode = 1  # 1表示要镜像,0表示不做镜像
             print(
                 "*************************进行800image 生成********************************************"
             )
@@ -430,7 +447,8 @@ class BaseDealImage(object):
                 cut_image_path=original_move_bg_image_path,
                 out_path=out_path,
                 image_deal_mode=is_image_deal_mode,
-                resize_mode=resize_mode,
+                # resize_mode=resize_mode,
+                resize_mode=1,#将这里得缩放模式改为强制不缩放 2025-10-22
                 out_pic_size=out_pic_size,
                 is_logo=True if i_n == 1 else False,
                 out_process_path_1=out_process_path_1,
@@ -507,8 +525,15 @@ class BaseDealImage(object):
             goods_art_item["folder_name"]
             for goods_art_item in all_goods_art_no_folder_data
         ]
+        total_progress = len(all_goods_art_no_folder_data)
+        finish_progress = 0
+        error_progress = 0
+        progress = {"status":"正在处理",
+                "current":finish_progress,
+                "total":total_progress,
+                "error":error_progress}
         sendAsyncMessage(
-            msg="开始处理抠图", goods_arts=goods_art_nos, status="开始处理"
+            msg="开始处理抠图", goods_arts=goods_art_nos, status="开始处理",progress=progress
         )
         error_goods_art_no_folder = []
         for goods_art_no_folder_data in all_goods_art_no_folder_data:
@@ -520,10 +545,17 @@ class BaseDealImage(object):
             images = [x for x in self.list_dir("{}/原始图".format(folder_path))]
             cutImageList = []
             goods_art_floder_name = goods_art_no_folder_data["folder_name"]
+            progress = {"status":"正在处理",
+                "current":finish_progress,
+                "total":total_progress,
+                "error":error_progress,
+                "goods_art_no":goods_art_floder_name
+                }
             sendAsyncMessage(
                 msg="正在抠图",
                 goods_arts=[goods_art_floder_name],
                 status="处理中",
+                progress=progress
             )
             for pic_file_name in images:
                 if windows:
@@ -571,11 +603,6 @@ class BaseDealImage(object):
                                     callback_func(
                                         "货号图{} 抠图处理超时~".format(file_name)
                                     )
-                                    # sendAsyncMessage(
-                                    #     msg="抠图处理超时",
-                                    #     goods_arts=[file_name],
-                                    #     status="抠图处理超时",
-                                    # )
                                     error_goods_art_no_folder.append(folder_path)
                                     im = None
                                 except BaseException as e:
@@ -585,11 +612,6 @@ class BaseDealImage(object):
                                         )
                                     )
                                     error_goods_art_no_folder.append(folder_path)
-                                    # sendAsyncMessage(
-                                    #     msg=f"抠图处理失败,原因{e}",
-                                    #     goods_arts=[file_name],
-                                    #     status="抠图处理失败",
-                                    # )
                                     im = None
 
                             if not im:
@@ -597,24 +619,31 @@ class BaseDealImage(object):
                                     "货号图{} 抠图处理失败~".format(file_name)
                                 )
                                 error_goods_art_no_folder.append(folder_path)
-                                # sendAsyncMessage(
-                                #     msg=f"抠图处理失败",
-                                #     goods_arts=[file_name],
-                                #     status="抠图处理失败",
-                                # )
                                 continue
                             else:
-                                # sendAsyncMessage(
-                                #     msg=f"完成抠图处理",
-                                #     goods_arts=[file_name],
-                                #     status="完成抠图处理",
-                                # )
                                 callback_func("货号图{} 抠图完成~".format(file_name))
+            progress = {
+                "status":"正在处理",
+                "current":finish_progress,
+                "total":total_progress,
+                "error":error_progress,
+                "goods_art_no":goods_art_floder_name
+                }
             if goods_art_floder_name not in error_goods_art_no_folder:
+                finish_progress+=1
                 sendAsyncMessage(
-                    msg="抠图完成",
+                    msg="正在处理",
                     goods_arts=[goods_art_floder_name],
-                    status="抠图完成",
+                    status="正在处理",
+                    progress=progress
+                )
+            else:
+                progress["status"] = "处理失败"
+                sendAsyncMessage(
+                    msg="处理失败",
+                    goods_arts=[goods_art_floder_name],
+                    status="处理失败",
+                    progress=progress
                 )
             if cutout_mode == "2":
                 dealCutout = DealCutout(windows=None, token=self.token)
@@ -622,14 +651,17 @@ class BaseDealImage(object):
                 dealCutout.run()
                 while True:
                     time.sleep(0.5)
-                    # if windows:
-                    #     if windows.state != 1:
-                    #         break
                     if dealCutout.state == 3:
                         if len(dealCutout.resultData) != len(cutImageList):
                             error_goods_art_no_folder.append(folder_path)
                         break
-
+        error_progress = len(error_goods_art_no_folder)
+        progress = {
+                "status":"处理完成",
+                "current":finish_progress,
+                "total":total_progress,
+                "error":error_progress
+                }
         if error_goods_art_no_folder:
             print("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
             callback_func("以下货号抠图失败~\n {}".format(error_goods_art_no_folder))
@@ -637,14 +669,17 @@ class BaseDealImage(object):
                 msg=f"抠图处理失败",
                 goods_arts=error_goods_art_no_folder,
                 status="抠图处理失败",
+                # progress=progress
             )
         else:
-            sendAsyncMessage(
-                msg=f"完成抠图处理",
-                goods_arts=goods_art_nos,
-                status="完成抠图处理",
-            )
-            callback_func("完成抠图处理")
+            pass
+        progress["status"] = "处理失败" if error_progress == total_progress else "处理完成"
+        sendAsyncMessage(
+                    msg="抠图完成",
+                    goods_arts=[],
+                    status="抠图完成",
+                    progress=progress
+                )
 
     def checkCutoutImage(self, image_dir: str, todo_goods_art_no_folder_name_list=None):
         """
@@ -1142,6 +1177,7 @@ class BaseDealImage(object):
             order_by="id",
             ascending=True,
         )
+        session.close()
         if result:
             return result.goods_art_no, result.image_index, result.image_deal_mode
         else:

+ 11 - 7
python/service/data.py

@@ -128,12 +128,17 @@ class DataModeGenerateDetail(DataBaseModel):
         print("goods_art_no_all_data===========>>>>>", "")
         print("goods_art_no_all_data===========>>>>>", "")
         print("goods_art_no_all_data===========>>>>>", "")
-        print("goods_art_no_all_data===========>>>>>", "")
+        print("goods_art_no_all_data===========>>>>>   111   ", return_dict)
         for folder_name, value in return_dict.items():
+            print("folder name ",value)
+            print("folder name ",folder_name)
+            print("folder name ",str(value["name"]))
+            print("folder name ",str(value["name"]) , goods_art_no_all_data)
+            print("=================================================")
             if value["type"] == "goods_art_no":
-                if value["name"] in goods_art_no_all_data:
+                if str(folder_name) in goods_art_no_all_data:
                     return_dict[folder_name]["data"] = goods_art_no_all_data[
-                        value["name"]
+                       folder_name
                     ]
 
         # ------------请求编码数据----------------------
@@ -145,17 +150,16 @@ class DataModeGenerateDetail(DataBaseModel):
         )
         for folder_name, value in return_dict.items():
             if value["type"] == "goods_number":
-                if value["name"] in goods_number_all_data:
+                if str(folder_name) in goods_number_all_data:
                     return_dict[folder_name]["data"] = goods_number_all_data[
-                        value["name"]
+                        str(folder_name)
                     ]
-
+        print("goods_art_no_all_data===========>>>>>  22222   ", return_dict)
         # 清空没有值的数据
         error_key = []
         for folder_name, value in return_dict.items():
             if not value["data"]:
                 error_key.append(folder_name)
-
         if error_key:
             for folder_name in error_key:
                 return_dict.pop(folder_name)

+ 19 - 13
python/service/deal_image.py

@@ -1,4 +1,4 @@
-import os
+import os,re
 
 from  natsort import natsorted,ns
 import shutil
@@ -30,8 +30,10 @@ class DealImage(BaseDealImage):
         return True
     def list_dir(self, path):
         listdir = os.listdir(path)
-        return natsorted(listdir, alg=ns.PATH)
-
+        sort_result = sorted(listdir, key=lambda x: int(re.findall(r'^(\d+)_', x)[0]) if re.findall(r'^(\d+)_', x) else 0)
+        # print("listdir   排序排序排序排序排序排序", sort_result)
+        # return natsorted(listdir, alg=ns.PATH)
+        return sort_result
     def get_date_time_original(self, file_path):
         with open(file_path, 'rb') as file_data:
             tags = exifread.process_file(file_data)
@@ -54,6 +56,7 @@ class DealImage(BaseDealImage):
             order_by="id",
             ascending=True,
         )
+        session.close()
         if result:
             return result.goods_art_no, result.image_index, result.image_deal_mode
         else:
@@ -181,7 +184,7 @@ class DealImage(BaseDealImage):
         # 遍历目标文件夹,获取有拍摄信息的图片,并按拍摄时间排序
         files = self.list_dir(image_dir)
         original_photo_list = []  # 原始图片列表
-        for file in files:
+        for file_idx,file in enumerate(files):
             # -----图片清洗
             file_path = image_dir + "/" + file
             if os.path.isdir(file_path):  # 忽略文件夹
@@ -198,12 +201,12 @@ class DealImage(BaseDealImage):
                 if _data:
                     # 能匹配上数据库
                     goods_art_no, image_index, image_deal_mode = _data
-                    print("832 与数据库匹配goods_art_no", file_name, date_time_original, goods_art_no)
+                    print("832 与数据库匹配goods_art_no", file_path,file_name, date_time_original, goods_art_no)
                     original_photo_list.append({"file_path": file_path,
                                                 "file": file,
                                                 "date_time_original": date_time_original,
                                                 "goods_art_no": goods_art_no,
-                                                "image_index": image_index,
+                                                "image_index": file_idx,
                                                 "real_goods_art_no": "",
                                                 "real_goods_number": "",
                                                 })
@@ -221,20 +224,22 @@ class DealImage(BaseDealImage):
             raise UnicornException("没有任何匹配的图片")
             return False, "没有任何匹配的图片"
         # 排序需要基于拍照的文件序号进行处理
-        original_photo_list.sort(
-            key=lambda x: "{}-{}-{}".format(x["goods_art_no"], x["image_index"], x["file"]))
+        # original_photo_list.sort(
+        #     key=lambda x: "{}-{}-{}".format(x["goods_art_no"], x["image_index"], x["file"]))
 
         # print(original_photo_list)
         # 对有拍摄信息的图片进行数据库比对,如有比对上,则移动至货号文件夹,否则移入历史文件夹
         total_num = len(original_photo_list)
         # 当天日期作为文件夹
         seconds = time.time()
-        output_path = "output/{f_name}".format(f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
+        output_path = "{}/{f_name}".format(settings.OUTPUT_DIR,f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
 
         # 遍历每个匹配好的数据进行处理
+        print(f"original_photo_list:",original_photo_list)
         n = 0
         for photo_dict in original_photo_list:
             n += 1
+            print("处理dict:",photo_dict)
             # 进度条
             goods_art_no = photo_dict["goods_art_no"]
             original_image_path = photo_dict["file_path"]
@@ -315,14 +320,15 @@ class DealImage(BaseDealImage):
                     continue
 
                 all_original_images = os.listdir(_path)  # 遍历货号原始图文件夹
-                goods_pic_total = len(all_original_images)
-                if not all_original_images:
+                sort_result = sorted(all_original_images, key=lambda x: int(re.findall(r'((\d+))', x)[0]) if re.findall(r'((\d+))', x) else 0)
+                goods_pic_total = len(sort_result)
+                if not sort_result:
                     continue
-                image_file = all_original_images[0]  # 取第一个货号图
+                image_file = sort_result[0]  # 取第一个货号图
                 image_file_path = "{}/{}/原始图/{}".format(
                     dir_path, goods_art_no_folder, image_file
                 )
-
+                # print("\033[1;32;40m 需要处理的200images,路径: \033[0m",image_file_path,all_original_images,sort_result)
                 if not os.path.exists(
                         "{}/{}/200images".format(dir_path, goods_art_no_folder)
                 ):

+ 176 - 45
python/service/grenerate_main_image_test.py

@@ -11,7 +11,7 @@ from functools import wraps
 from .multi_threaded_image_saving import ImageSaver
 from .get_mask_by_green import GetMask
 from middleware import UnicornException
-
+from logger import logger
 def time_it(func):
     @wraps(func)  # 使用wraps来保留原始函数的元数据信息
     def wrapper(*args, **kwargs):
@@ -103,6 +103,8 @@ class GeneratePic(object):
         bg = Image.new(mode="RGBA", size=im_png.size, color=(255, 255, 255, 255))
         bg.paste(im_png, mask=im_png)
         bg.paste(im_jpg, mask=mask)  # 粘贴有阴影的地方
+        if image_high > y2 + 20:
+            lowest_y = y2 + 20
         if self.is_test:
             _bg = bg.copy()
             draw = ImageDraw.Draw(_bg)
@@ -348,7 +350,87 @@ class GeneratePic(object):
         time.sleep(3)
         if output_queue is not None:
             output_queue.put(True)
+    def paste_img(self,image, top_img, base="nw", value=(0, 0), ):
+            """
+            {
+                "command": "paste_img",
+                "im": 需要粘贴的图片
+                "pos": {"plugins_mode": "relative",  # pixel
+                        "base": "center",  # nw,nc,ne,ec ... 各个方向参考点
+                        "value": (100, 100),
+                        "percentage": (0.5, 0.5),
+                        },
+                "margins": (0, 0, 0, 0),  # 上下左右边距
+            }
+            """
+            value = (int(value[0]), int(value[1]))
+            # 处理默认值
+            base = "nw" if not base else base
+            top, down, left, right = 0, 0, 0, 0
+
+            # 基于右边,上下居中
+            if base == "ec" or base == "ce":
+                p_x = int(image.width - (top_img.width + value[0]))
+                p_y = int((image.height - top_img.height) / 2) + value[1]
+
+            # 基于顶部,左右居中
+            if base == "nc" or base == "cn":
+                # 顶部对齐
+                deviation_x, deviation_y = int((image.width - top_img.width) / 2), int(
+                    (image.height - top_img.height) / 2
+                )
+                p_x = deviation_x + value[0] + left
+                p_y = value[1]
+
+            # 基于右上角
+            if base == "en" or base == "ne":
+                p_x = int(image.width - (top_img.width + value[0])) + left
+                p_y = value[1]
+
+            # 基于左上角
+            if base == "nw" or base == "wn":
+                deviation_x, deviation_y = 0, 0
+                p_x, p_y = value
+
+            # 基于底部,左右居中
+            if base == "cs" or base == "sc":
+                deviation_x, deviation_y = int((image.width - top_img.width) / 2), int(
+                    (image.height - top_img.height) / 2
+                )
+
+                p_y = image.height - (top_img.height + value[1] + down)
+                p_x = deviation_x + value[0] + left
+
+            # 上下左右居中
+            if base == "center" or base == "cc":
+                deviation_x, deviation_y = int((image.width - top_img.width) / 2), int(
+                    (image.height - top_img.height) / 2
+                )
+                p_x = deviation_x + value[0] + left
+                p_y = deviation_y + value[1] + top
+
+            # 基于左下角
+            if base == "sw" or base == "ws":
+                # deviation_x, deviation_y = 0, int((img.height - img_1.height))
+                p_x = value[0] + left
+                p_y = image.height - (top_img.height + value[1] + down)
+
+            # 基于左边,上下居中
+            if base == "wc" or base == "cw":
+                p_x = value[0] + left
+                p_y = int((image.height - top_img.height) / 2) + value[1] + top
 
+            # 基于右下角
+            if base == "es" or base == "se":
+                p_x = int(image.width - (top_img.width + value[0])) + left
+                p_y = image.height - (top_img.height + value[1] + down) + top
+
+            try:
+                image.paste(top_img, box=(p_x, p_y), mask=top_img)
+            except:
+                image.paste(top_img, box=(p_x, p_y), mask=top_img.convert("RGBA"))
+
+            return image
     @time_it
     def run(
         self,
@@ -384,14 +466,20 @@ class GeneratePic(object):
             output_queue = kwargs["output_queue"]
         else:
             output_queue = None
-
+        # image_deal_mode = 0#不翻转图像
+        padding_800image = settings.getSysConfigs(
+            "basic_configs", "padding_800image", 100
+        )
         # ==========先进行剪切原图
         _s = time.time()
-        orign_im = Image.open(image_path)  # 原始图
+        with Image.open(image_path) as orign_im:
+            # 复制图像以便后续操作
+            orign_im = orign_im.copy()
         print("242  need_time_1:{}".format(time.time() - _s))
-
         orign_x, orign_y = orign_im.size
-        cut_image = Image.open(cut_image_path)  # 原始图的已扣图
+        with Image.open(cut_image_path) as cut_image:
+            # 复制图像以便后续操作
+            cut_image = cut_image.copy()
         cut_image, new_box = get_mini_crop_img(img=cut_image)
         im_shadow = orign_im.crop(new_box)  # 切图
         new_x, new_y = im_shadow.size
@@ -480,46 +568,70 @@ class GeneratePic(object):
         # 不生成主图时直接退出
         if not out_path:
             return True
-
-        # im_shadow.show()
-        # =====================主图物体的缩放依据大小
-        if max_box:
-            im_shadow = to_resize(_im=im_shadow, width=max_box[0], high=max_box[1])
-            cut_image = to_resize(_im=cut_image, width=max_box[0], high=max_box[1])
-        else:
-            if resize_mode is None:
-                im_shadow = to_resize(_im=im_shadow, width=1400, high=1400)
-                cut_image = to_resize(_im=cut_image, width=1400, high=1400)
-
-            elif resize_mode == 1:
-                im_shadow = to_resize(_im=im_shadow, width=1400, high=1400)
-                cut_image = to_resize(_im=cut_image, width=1400, high=1400)
-
-            elif resize_mode == 2:
-                # todo 兼容长筒靴等,将图片大小限制在一个指定的box内
-                im_shadow = to_resize(_im=im_shadow, width=650)
-                cut_image = to_resize(_im=cut_image, width=650)
-                # 再次检查需要约束缩小到一定高度,适应长筒靴
-                _im_x, _im_y = cut_image.size
-                if _im_y > 1400:
-                    im_shadow = to_resize(_im=im_shadow, high=1400)
-                    cut_image = to_resize(_im=cut_image, high=1400)
-
-                # if im_shadow.height <= im_shadow.width * 1.2:
-                #     im_shadow = to_resize(_im=im_shadow, width=650)
-                #     cut_image = to_resize(_im=cut_image, width=650)
-                # else:
-                #     im_shadow = to_resize(_im=im_shadow, high=1400)
-                #     cut_image = to_resize(_im=cut_image, high=1400)
-
         if image_deal_mode == 1:
             # 翻转
             im_shadow = im_shadow.transpose(Image.FLIP_LEFT_RIGHT)
             cut_image = cut_image.transpose(Image.FLIP_LEFT_RIGHT)
+        image_margin = int(padding_800image)
+        bg_size = (1600, 1600)
+        _offset_x, _offset_y = 0, 0
+        scale_rate = 1
+        # im_shadow.show()
+        # =====================主图物体的缩放依据大小
+        if image_margin is not None:
+            _bbox = cut_image.getbbox()
+            _x, _y = _bbox[0], _bbox[1]
+            _w, _h = _bbox[2] - _bbox[0], _bbox[3] - _bbox[1]
+            # 中心偏移量
+            offset_x, offset_y = _x - (cut_image.width - _w) / 2, _y - (cut_image.height - _h) / 2,
+            # print("中心偏移量:", offset_x, offset_y)
+            # 透明底最小矩形
+            scale_rate = self.get_scale(base_by_box=(bg_size[0] - image_margin * 2, bg_size[1] - image_margin * 2), image_size=(_w, _h))
+            # 计算缩放比例,以及顶点相对位置
+            # print("缩放比例:", scale_rate)
+            # 偏移量
+            _offset_x, _offset_y = offset_x * scale_rate, offset_y * scale_rate
+            # print("偏移量:", _offset_x, _offset_y)
+            # 阴影图缩放尺寸
+            cut_image = to_resize(_im=cut_image, width=cut_image.width * scale_rate)
+            im_shadow = to_resize(_im=im_shadow, width=im_shadow.width * scale_rate)
+
+        else:
+            if max_box:
+                im_shadow = to_resize(_im=im_shadow, width=max_box[0], high=max_box[1])
+                cut_image = to_resize(_im=cut_image, width=max_box[0], high=max_box[1])
+            else:
+                size_defind = 1400
+                if resize_mode is None:
+                    im_shadow = to_resize(_im=im_shadow, width=size_defind, high=size_defind)
+                    cut_image = to_resize(_im=cut_image, width=size_defind, high=size_defind)
+
+                elif resize_mode == 1:
+                    im_shadow = to_resize(_im=im_shadow, width=size_defind, high=size_defind)
+                    cut_image = to_resize(_im=cut_image, width=size_defind, high=size_defind)
+
+                elif resize_mode == 2:
+                    # todo 兼容长筒靴等,将图片大小限制在一个指定的box内
+                    im_shadow = to_resize(_im=im_shadow, width=650)
+                    cut_image = to_resize(_im=cut_image, width=650)
+                    # 再次检查需要约束缩小到一定高度,适应长筒靴
+                    _im_x, _im_y = cut_image.size
+                    if _im_y > 1400:
+                        im_shadow = to_resize(_im=im_shadow, high=1400)
+                        cut_image = to_resize(_im=cut_image, high=1400)
+
+                    # if im_shadow.height <= im_shadow.width * 1.2:
+                    #     im_shadow = to_resize(_im=im_shadow, width=650)
+                    #     cut_image = to_resize(_im=cut_image, width=650)
+                    # else:
+                    #     im_shadow = to_resize(_im=im_shadow, high=1400)
+                    #     cut_image = to_resize(_im=cut_image, high=1400)
 
-        # 创建底层背景
-        image_bg = Image.new("RGB", (1600, 1600), (255, 255, 255))
 
+        # 创建底层背景
+        image_bg = Image.new("RGB", bg_size, (255, 255, 255))
+        image_bg = self.paste_img(image=image_bg, top_img=im_shadow, base="cc", value=(_offset_x * -1, _offset_y * -1))
+        image_bg = self.paste_img(image=image_bg, top_img=cut_image, base="cc", value=(_offset_x * -1, _offset_y * -1))
         image_bg_x, image_bg_y = image_bg.size
         image_x, image_y = im_shadow.size
 
@@ -581,10 +693,12 @@ class GeneratePic(object):
                 file_without_suffix = out_path
                 suffix = ""
             # 单独拼接字符串示例
-            new_file_path = f"{file_without_suffix}_{imageSize}.{suffix}"
-            if imageSize < 1600:
+            image_size_int = int(imageSize)
+            image_size_str = str(imageSize)
+            new_file_path = f"{file_without_suffix}_{image_size_str}.{suffix}"
+            if image_size_int < 3000:
                 image_bg = image_bg.resize(
-                    (imageSize, imageSize), resample=settings.RESIZE_IMAGE_MODE
+                    (image_size_int, image_size_int), resample=settings.RESIZE_IMAGE_MODE
                 )
                 if out_pci_mode == ".jpg":
                     self.saver.save_image(
@@ -627,7 +741,24 @@ class GeneratePic(object):
                     _format=new_format,
                 )
                 # image_bg.save(out_path)
-
-        if output_queue is not None:
-            output_queue.put(True)
+        # 在函数结束时使用更安全的关闭方式
+        # 清理所有可能打开的图片对象
+        for img_var in ['orign_im', 'cut_image', 'logo_im', 'out_image_1', 'out_image_2']:
+            if img_var in locals():
+                img = locals()[img_var]
+                if hasattr(img, 'close'):
+                    try:
+                        img.close()
+                    except Exception as e:
+                        logger.warning(f"关闭图片对象 {img_var} 时出错: {e}")
+            if output_queue is not None:
+                output_queue.put(True)
         return True
+    def get_scale(self,base_by_box, image_size):
+        box_width, box_height = int(base_by_box[0]), int(base_by_box[1])
+        width, height = image_size[0], image_size[1]
+        if box_width / box_height < width / height:
+            scale = box_width / width
+        else:
+            scale = box_height / height
+        return scale

+ 2 - 0
python/service/image_pic_deal.py

@@ -32,6 +32,7 @@ class OnePicDeal(object):
             print("自动识别----->这是左脚")
         else:
             print("自动识别----->这是右脚")
+        im.close()
         return flag
 
     def check_shoe_is_right_by_pixel(self, im=None, image_path=None):
@@ -57,6 +58,7 @@ class OnePicDeal(object):
                 left_f_num += 1
             else:
                 left_f_num -= 1
+        im.close()
         if left_f_num > 0:
             return True
         else:

+ 5 - 2
python/service/match_and_cutout_mode_control/base_deal_image_v2.py

@@ -260,8 +260,11 @@ class BaseDealImage(object):
         is_image_deal_mode = 0
 
         # 删除目录再新建
-        if os.path.exists('{}/阴影图处理'.format(folder_path)):
+        try:
+          if os.path.exists('{}/阴影图处理'.format(folder_path)):
             shutil.rmtree('{}/阴影图处理'.format(folder_path))
+        except:
+          print('An exception occurred')
 
         self.crate_all_folders(folder_path)
 
@@ -975,7 +978,7 @@ class BaseDealImage(object):
         total_num = len(original_photo_list)
         # 当天日期作为文件夹
         seconds = time.time()
-        output_path = "output/{f_name}".format(f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
+        output_path = "{output}/{f_name}".format(output=settings.OUTPUT_DIR,f_name=time.strftime("%Y-%m-%d", time.localtime(seconds)))
 
         # 遍历每个匹配好的数据进行处理
         n = 0

+ 1 - 1
python/service/match_and_cutout_mode_control/module_matching_photos_v2.py

@@ -904,7 +904,7 @@ class MatchingPhotos(MineQWidget):
         total_num = len(original_photo_list)
         # 当天日期作为文件夹
         seconds = time.time()
-        output_path = "output/{f_name}".format(
+        output_path = "{output}/{f_name}".format(output=settings.OUTPUT_DIR,
             f_name=time.strftime("%Y-%m-%d", time.localtime(seconds))
         )
 

+ 1 - 1
python/service/matching_photos/module_matching_photos.py

@@ -553,7 +553,7 @@ class MatchingPhotos(MineQWidget):
         total_num = len(original_photo_list)
         # 当天日期作为文件夹
         seconds = time.time()
-        output_path = "output/{f_name}".format(
+        output_path = "{output}/{f_name}".format(output=settings.OUTPUT_DIR,
             f_name=time.strftime("%Y-%m-%d", time.localtime(seconds))
         )
 

+ 1 - 0
python/service/multi_threaded_image_saving.py

@@ -87,6 +87,7 @@ class ImageSaver:
                     image.save(out_path, quality=quality, format=_format)
             else:
                 image.save(out_path, format=_format)
+        image.close()
 
     def get_completed_images(self, file_path):
         """

+ 113 - 40
python/service/online_request/module_online_data.py

@@ -7,7 +7,9 @@ from utils.common import message_queue
 from middleware import UnicornException
 from PIL import Image
 import io, time
+from logger import logger
 
+# logger = logging.getLogger(__name__)
 
 class JsonEncoder(json.JSONEncoder):
     """Convert numpy classes to JSON serializable objects."""
@@ -110,7 +112,7 @@ class AIGCDataRequest(object):
             # 如果保存为JPG等不支持透明度的格式,转换为RGB并使用白色背景
             background = background.convert("RGB")
             background.save(output_path)
-
+        source_img.close()
         return background
 
     def generateProductScene(self, local_path, prompt, save_path):
@@ -124,41 +126,102 @@ class AIGCDataRequest(object):
             "gemini_model": "gemini-2.5-flash-image-preview",
         }
         """生成场景图"""
-        url = settings.DOMAIN + "/api/ai_image/inspired/command_to_image"
+        try:
+            url = settings.DOMAIN + "/api/ai_image/inspired/command_to_image"
+            resultData = self.s.post(url, data=data, headers=self.post_headers, timeout=80).json()
+
+            code = resultData.get("code", 0)
+            message = resultData.get("message", "")
+            if code != 0:
+                raise UnicornException(message)
+            image_arr = resultData.get("data", None).get("image", [])
+            if len(image_arr) == 0:
+                raise UnicornException("场景图生成失败")
+            image_url = image_arr[0]
+            save_image_path = download_image_with_pil(image_url, save_path)
+            return save_image_path
+        except:
+          raise UnicornException("场景图生成失败")
+
+    def generateProductSceneQW(self, local_path, prompt, save_path):
+        '''千问生成场景图'''
+        imageUrl = self.uploadImage(local_path)
+        data = {
+            "machine_type": 0,  # 0鞋;1服装
+            "generate_type": 0,  # 生成类型,这里指代得是场景图还是模特图;0场景图;1模特图
+            "base_image": imageUrl,
+            "prompt": prompt
+        }
+        """生成场景图"""
+        url = settings.DOMAIN + "/api/ai_image/main/image_edit_generate"
         resultData = self.s.post(url, data=data, headers=self.post_headers).json()
 
         code = resultData.get("code", 0)
         message = resultData.get("message", "")
         if code != 0:
             raise UnicornException(message)
-        image_arr = resultData.get("data", None).get("image", [])
-        if len(image_arr) == 0:
+        image_url = resultData.get("data", None).get("image_url", '')
+        if image_url == "" or image_url is None:
             raise UnicornException("场景图生成失败")
-        image_url = image_arr[0]
         save_image_path = download_image_with_pil(image_url, save_path)
         return save_image_path
 
-    def searchProgress(self, id):
-        """查询进度"""
-        url = settings.DOMAIN + "/api/ai_image/main/search_bacth_progress"
-        data = {"site": 1, "generate_ids": [id], "type": "aigc_pro"}
-        resultData = self.s.post(url, json=data, headers=self.post_headers)
-        resultData = resultData.json()
+    def generateModelShoesQW(self, local_path, model_id, save_path):
+        '''千问生成场景图'''
+        imageUrl = self.uploadImage(local_path)
+        data = {
+            "machine_type": 0,  # 0鞋;1服装
+            "generate_type": 1,  # 生成类型,这里指代得是场景图还是模特图;0场景图;1模特图
+            "base_image": imageUrl,
+            "model_template_id": model_id,
+        }
+        """生成场景图"""
+        url = settings.DOMAIN + "/api/ai_image/main/image_edit_generate"
+        resultData = self.s.post(url, data=data, headers=self.post_headers).json()
 
         code = resultData.get("code", 0)
         message = resultData.get("message", "")
         if code != 0:
             raise UnicornException(message)
-        data_result = resultData.get("data", [])
-        if len(data_result) == 0:
+        image_url = resultData.get("data", None).get("image_url", '')
+        if image_url == "" or image_url is None:
+            raise UnicornException("模特图生成失败")
+        save_image_path = download_image_with_pil(image_url, save_path)
+        return save_image_path
+
+    def searchProgress(self, id):
+        """查询进度"""
+        try:
+            url = settings.DOMAIN + "/api/ai_image/main/search_bacth_progress"
+            data = {"site": 1, "generate_ids": [id], "type": "aigc_pro"}
+            resultData = self.s.post(url, json=data, headers=self.post_headers, timeout=10)
+            resultData = resultData.json()
+            code = resultData.get("code", 0)
+            message = resultData.get("message", "")
+            if code != 0:
+                raise UnicornException(message)
+            data_result = resultData.get("data", [])
+            print("查询进度", data_result)
+            logger.info(f"查询进度:{data_result}")
+            if len(data_result) == 0:
+                return -1, None
+            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("查询进度超时")
+            return -1, None
+        except Exception as e:
+            print(f"查询进度异常: {e}")
             return -1, None
-        data_item = data_result[0]
-        status = data_item.get("status", -1)
-        if status in [0,1]:
-            return status, None
-        result_image_urls = data_item.get("result_image_urls", [])
-        result_image = result_image_urls[0] if len(result_image_urls) > 0 else None
-        return status, result_image
 
     def generateUpperShoes(self, local_path, model_id, save_path):
         """生成上脚图"""
@@ -184,18 +247,24 @@ class AIGCDataRequest(object):
         if len(generate_ids) == 0:
             raise UnicornException("模特图生成失败")
         generate_id = generate_ids[0]
-        search_times = 60
+        search_times = 80
         status = 0
         result_image = None
         print("generate_id", generate_id)
         while search_times > 0:
-            print(f"查询第{search_times}次")
+            print(f"模特图查询第{search_times}次")
+            logger.info(f"模特图查询第{search_times}次")
             status, result_image = self.searchProgress(generate_id)
-            if status in [-1, 2]:
+            # status: -1=失败, 0=排队中, 1=进行中, 2=完成
+            if status == 2:  # 完成
                 break
+            if status == -1:  # 失败
+                break
+            # status为0(排队中)或1(进行中)时继续查询
             time.sleep(1)
             search_times -= 1
-        if not result_image:
+        # 循环结束后检查最终状态
+        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)
@@ -445,7 +514,7 @@ class OnlineDataRequest(object):
         resultData = self.s.post(
             url, files={"file": open(local_path, "rb")}, headers=post_headers
         ).json()
-        
+
         return resultData["data"]["url"]
 
     def get_current_menu(self):
@@ -602,7 +671,7 @@ class OnlineDataRequest(object):
         # print("上传商品api==>url", url)
         # print("上传第三方数据打印", params)
         resultData = self.s.post(url, data=postData, headers=post_headers).json()
-        
+
         print("上传商品api==>resultData", resultData)
         return resultData
 
@@ -646,6 +715,8 @@ class OnlineDataRequest(object):
                 for skuIdx, sku_data in enumerate(sku_list_basic):
                     sku_goods_art_no = sku_data.get("货号", "")
                     color_name = sku_data.get("颜色名称", "")
+                    size = sku_data.get("尺码", "")
+                    # 尺码
                     mainImages = sku_data.get("800x800", [])
                     if not mainImages:
                         continue
@@ -657,7 +728,7 @@ class OnlineDataRequest(object):
                         "originalPrice": float(goods_price),
                         "newSkuWeight": int(1),
                         "skuMainImageUrl": str(imageUrl),
-                        "skuName": f"颜色:{color_name}",
+                        "skuName": f"颜色:{color_name};尺码:{size}",
                         "sellingPrice": float(goods_price),
                         "quantity": int(quantity),
                         "showOrder": int(skuIdx + 1),
@@ -807,23 +878,25 @@ class GetOnlineDataHLM(OnlineDataRequest):
             return {}
 
         for data in response_data["data"]:
-            goods_number_data[data["goods_art_no"]] = {}
-            goods_number_data[data["goods_art_no"]]["商品货号"] = data[
+            goods_art_no = str(data["goods_art_no"])
+            goods_number_data[goods_art_no] = {}
+            goods_number_data[goods_art_no]["商品货号"] = data[
                 "goods_art_no"
             ].upper()
-            goods_number_data[data["goods_art_no"]]["款号"] = data[
+            goods_number_data[goods_art_no]["款号"] = data[
                 "goods_number"
             ].upper()
-            goods_number_data[data["goods_art_no"]]["商品面料"] = data["fabric"]
-            goods_number_data[data["goods_art_no"]]["商品内里"] = data["lining"]
-            goods_number_data[data["goods_art_no"]]["商品鞋底"] = data["sole"]
-            goods_number_data[data["goods_art_no"]]["鞋垫"] = data["insole"]
-            goods_number_data[data["goods_art_no"]]["颜色名称"] = data["color"]
-            goods_number_data[data["goods_art_no"]]["商品标题"] = data["goods_title"]
-            goods_number_data[data["goods_art_no"]]["商品价格"] = data["retail_price"]
-            goods_number_data[data["goods_art_no"]]["性别"] = data["gender"]
-            goods_number_data[data["goods_art_no"]]["token"] = self.token
-
+            goods_number_data[goods_art_no]["商品面料"] = data["fabric"]
+            goods_number_data[goods_art_no]["商品内里"] = data["lining"]
+            goods_number_data[goods_art_no]["商品鞋底"] = data["sole"]
+            goods_number_data[goods_art_no]["鞋垫"] = data["insole"]
+            goods_number_data[goods_art_no]["颜色名称"] = data["color"]
+            goods_number_data[goods_art_no]["商品标题"] = data["goods_title"]
+            goods_number_data[goods_art_no]["商品价格"] = data["retail_price"]
+            goods_number_data[goods_art_no]["尺码"] = data["size"]
+            goods_number_data[goods_art_no]["性别"] = data["gender"]
+            goods_number_data[goods_art_no]["token"] = self.token
+        print("货号数据:", goods_number_data)
         return goods_number_data
 
     def uploadImage(self, local_path: str) -> str:

+ 130 - 232
python/service/run_main.py

@@ -22,7 +22,7 @@ from .base_deal import BaseDealImage
 from middleware import UnicornException
 from settings import recordDataPoint
 import asyncio
-
+from utils.common import message_queue
 
 class RunMain:
     # run_end_sign = Signal(dict)
@@ -186,22 +186,10 @@ class RunMain:
 
     # 抠图校验后的回调函数处理
     def check_for_cutout_image_first_call_back(self, return_data):
-        # return_data = {
-        #     "code": 99,
-        #     "message": "",
-        #     "data": {
-        #         "all_goods_art_no_folder_data": [],
-        #     },
-        # }
         code = return_data["code"]
         config_data = return_data["data"]["config_data"]
         config_data["sign_text"] = ""
         if code != 0:
-            # self.windows.show_message(return_data["message"])
-            # self.show_progress_detail(return_data["message"])
-            # _dialog_dict = {"text": return_data["message"],
-            #                 "windows": self,
-            #                 }
             raise UnicornException(return_data["message"])
 
         do_next = False
@@ -233,27 +221,6 @@ class RunMain:
         elif button_1 == "继续" and button_2 is None and button_3 is None:
             do_next = True
         else:
-            # print("runmain  179----------------")
-            # # print(self)
-            # # print(self.windows)
-            # _dialog_dict = {"text": text,
-            #                 "button_1": button_1,
-            #                 "button_2": button_2,
-            #                 "button_3": button_3,
-            #                 "windows": self,
-            #                 }
-            # self.show_dialog_sign.emit(_dialog_dict)
-            # # self.exec_()
-            # # 等待事件被设置
-            # self.event.wait()
-            # print("self.dialog_result", self.dialog_result)
-            # #
-            # # my_dialog = DialogShow(self.windows, text=text, button_1=button_1, button_2=button_2,
-            # #                        button_3=button_3)
-            # # ret = my_dialog.exec()
-            # print("460  ===============my_dialog.flag_name===============")
-            # print(my_dialog.flag_name)
-
             if "移除" in self.dialog_result:
                 for error_folder_data in [
                     x for x in all_goods_art_no_folder_data if x["label"] == "错误"
@@ -270,28 +237,6 @@ class RunMain:
             goods_art_no_folder_data["folder_name"]
             for goods_art_no_folder_data in all_goods_art_no_folder_data
         ]
-        # try:
-        #     loop = asyncio.get_event_loop()
-        #     loop.create_task(sendSocketMessage(
-        #         code=0,
-        #         msg="开始处理抠图",
-        #         data={
-        #             "status": "进行中",
-        #             "goods_art_nos": goods_arts,
-        #         },
-        #         msg_type="segment_progress",
-        #     ))
-        # except:
-        #     print('An exception occurred')
-        #     asyncio.run(sendSocketMessage(
-        #         code=0,
-        #         msg="开始处理抠图",
-        #         data={
-        #             "status": "进行中",
-        #             "goods_art_nos": goods_arts,
-        #         },
-        #         msg_type="segment_progress",
-        #     ))
         if do_next:
             all_goods_art_no_folder_data = [
                 x for x in all_goods_art_no_folder_data if x["label"] == "待处理"
@@ -312,32 +257,6 @@ class RunMain:
             return new_func
         else:
             print("已结束抠图处理")
-            # try:
-            #     loop = asyncio.get_event_loop()
-            #     loop.create_task(
-            #         sendSocketMessage(
-            #             code=0,
-            #             msg="抠图结束",
-            #             data={
-            #                 "status": "已完成",
-            #                 "goods_art_nos": goods_arts,
-            #             },
-            #             msg_type="segment_progress",
-            #         )
-            #     )
-            # except:
-            #     print('An exception occurred')
-            #     asyncio.run(
-            #         sendSocketMessage(
-            #             code=0,
-            #             msg="抠图结束",
-            #             data={
-            #                 "status": "已完成",
-            #                 "goods_art_nos": goods_arts,
-            #             },
-            #             msg_type="segment_progress",
-            #         )
-            #     )
             return True
 
     def do_run_cutout_image(
@@ -522,18 +441,9 @@ class RunMain:
         _result = {"code": 99, "message": "无法解析到数据,请检查登录企业"}
         print("is_use_excel", is_use_excel)
         if not is_use_excel:
-            if settings.PROJECT == "红蜻蜓":
-                # goods_no_dict输出为文件夹下涉及到的所有款为key的字典,后续通过解析字典,进行提取对应文件夹
-                _result = self.data_mode_generate_detail.get_basic_goods_art_data_by_hqt_and_hlm(
-                    folder_name_list
-                )
-
-            elif settings.PROJECT == "惠利玛":
-                if settings.Company:
-                    if "惠利玛" in settings.Company:
-                        _result = self.data_mode_generate_detail.get_basic_goods_art_data_by_hqt_and_hlm(
+            _result = self.data_mode_generate_detail.get_basic_goods_art_data_by_hqt_and_hlm(
                             folder_name_list
-                        )
+                        )            
         else:
             keys = settings.keys
             _result = (
@@ -543,7 +453,7 @@ class RunMain:
                     keys,
                 )
             )
-            print("打印=======>>>>>>>_result=============>", _result)
+        print("打印=======>>>>>>>_result=============>", _result)
         if _result["code"] == 0:
             remote_data = _result["data"]
         else:
@@ -561,7 +471,17 @@ class RunMain:
         print("temp_class====>", temp_class)
         print("temp_class====>", temp_name)
         # 获取所有文件夹基础数据内容  检查不满足要求的文件不满足要求移动到错误文件夹
-        need_view_list = temp_class[temp_name].need_view
+        # 在访问 temp_class[temp_name].need_view 前增加检查
+        if temp_name not in temp_class or temp_class[temp_name] is None:
+            raise UnicornException(f"模板 {temp_name} 未正确初始化或不存在")
+
+        # 确保 temp_class[temp_name] 是可调用的
+        if not callable(temp_class[temp_name]):
+            raise UnicornException(f"模板 {temp_name} 不是有效的可调用对象")
+        try:
+          need_view_list = temp_class[temp_name].need_view
+        except KeyError as ke:
+          raise UnicornException("未选择详情页模板,请检查")
         _all_dir_info_data = get_all_dir_info_and_pic_info(
             image_dir, folder_name_list, need_view_list
         )
@@ -604,14 +524,14 @@ class RunMain:
                         "folder_path": "{}/{}".format(image_dir, one_folder),
                     }
                 )
-                return_data["message"] += "文件夹:{} 找不到对应数据\n".format(
+                return_data["message"] += "文件夹:{} 在系统资料中找不到对应数据\n".format(
                     one_folder
                 )
                 return_data["data"]["config_data"]["success_handler"].append(
                     {
                         "goods_art_no": one_folder,
                         "success": False,
-                        "info": f"文件夹:{one_folder} 找不到对应数据",
+                        "info": f"文件夹:{one_folder} 在系统资料中找不到对应数据",
                     }
                 )
 
@@ -675,7 +595,7 @@ class RunMain:
 
         # 如果没有有效数据则进行退出
         if not goods_no_dict:
-            return_data["message"] += "没有任何有效数据\n"
+            return_data["message"] += "在系统资料中没有查询到有效数据\n"
             return return_data
 
         # 校验无误的文件夹数据  goods_no_dict为最终有效数据
@@ -732,8 +652,11 @@ class RunMain:
             if goods_no not in goods_no_need_temps:
                 continue
             for __temp_name in goods_no_need_temps[goods_no]:
-                _path = "{}/{}/{}/{}".format(
-                    image_dir, "软件-详情图生成", __temp_name, goods_no
+                # _path = "{}/{}/{}/{}".format(
+                #     image_dir, "软件-详情图生成", __temp_name, goods_no
+                # )
+                _path = "{}/{}/切片图-{}".format(
+                    image_dir, f"详情图-{goods_no}",__temp_name
                 )
                 if not os.path.exists(_path):
                     print("款号详情图不存在", _path)
@@ -790,12 +713,46 @@ class RunMain:
 
         return_data["code"] = 0
         return return_data
-
+    def sendAsyncMessage(self,msg="", goods_arts=[], status="",progress={}):
+        """异步发送消息"""
+        data = {
+            "code": 0,
+            "msg": msg,
+            "status": 2,
+            "data": {
+                "status": status,
+                "goods_art_nos": goods_arts,
+            },
+            "progress":{
+                    "msg_type":"detail_progress",
+                    "name":"详情页",
+                    "goods_art_no":progress.get("goods_art_no"),
+                    "status":progress.get("status"),
+                    "current":progress.get("current",0),
+                    "total":progress.get("total",0),
+                    "error":progress.get("error",0),
+                    "folder":progress.get("folder",None)
+                },
+            "msg_type": "detail_progress",
+        }
+        print("\033[1;32;40m 详情页消息 \033[0m",data)
+        message_queue.put_nowait(data)
     def move_error_folders(self, one_path, target_folder, message=""):
         if os.path.exists(one_path):
             check_path(target_folder)
             move_folders(path_list=[one_path], target_folder=target_folder)
-
+    '''
+    total_progress = len(all_goods_art_no_folder_data)
+        finish_progress = 0
+        error_progress = 0
+        progress = {"status":"正在处理",
+                "current":finish_progress,
+                "total":total_progress,
+                "error":error_progress}
+        sendAsyncMessage(
+            msg="开始处理抠图", goods_arts=goods_art_nos, status="开始处理",progress=progress
+        )
+    '''
     def check_for_detail_first_call_back(self, data):
         # 首次数据校验的信息返回
         # self.show_message(text="22222222222222222222222")
@@ -922,7 +879,8 @@ class RunMain:
         image_dir = config_data["image_dir"]
 
         # 详情图生成结果文件夹
-        out_put_dir = "{}\软件-详情图生成".format(image_dir)
+        # out_put_dir = "{}\软件-详情图生成".format(image_dir)
+        out_put_dir = "{}".format(image_dir)
         if settings.IS_TEST:
             print("==============_goods_no_dict  打印=================")
 
@@ -932,9 +890,34 @@ class RunMain:
 
         all_detail_path_list = []
         out_put_dir_resp = ""
+        detail_total_progress = len(finally_goods_no_need_temps.items())
+        detail_finish_progress = 0
+        detail_error_progress = 0
+        detail_progress = {"status":"正在处理", "current":detail_finish_progress, "total":detail_total_progress, "error":detail_error_progress}
+        self.sendAsyncMessage(
+            msg="准备处理详情页",
+            goods_arts=[],
+            status="准备处理详情页",
+            progress=detail_progress
+        )
         for goods_no, temp_name_list in finally_goods_no_need_temps.items():
             for _temp_name in temp_name_list:
                 try:
+                    detail_finish_progress+=1
+                    detail_progress = {
+                        "status":"正在处理",
+                        "goods_art_no":goods_no, 
+                        "current":detail_finish_progress, 
+                        "total":detail_total_progress, 
+                        "error":detail_error_progress,
+                        "folder":""
+                        }
+                    self.sendAsyncMessage(
+                        msg="正在处理详情页",
+                        goods_arts=[],
+                        status="正在处理详情页",
+                        progress=detail_progress
+                    )
                     # if _temp_name != "xiaosushuoxie-4":
                     #     continue
                     assigned_page_list = []
@@ -953,12 +936,16 @@ class RunMain:
                                     if _key in temp_info_data:
                                         temp_info_data[_key] = _key_value
                     print("goods_no:{},_temp_name:{}".format(goods_no, _temp_name))
-                    out_put_dir_resp = "{}/详情模板{}/{}".format(
-                        out_put_dir, _temp_name, goods_no
-                    )
-                    all_detail_path_list.append(
-                        "{}/详情模板{}/{}".format(out_put_dir, _temp_name, goods_no)
+                    # out_put_dir_resp = "{}/详情模板{}/{}".format(
+                    #     out_put_dir, _temp_name, goods_no
+                    # )
+                    out_put_dir_resp = "{}/详情图-{}".format(
+                        out_put_dir, goods_no
                     )
+                    # all_detail_path_list.append(
+                    #     "{}/详情模板{}/{}".format(out_put_dir, _temp_name, goods_no)
+                    # )
+                    all_detail_path_list.append(out_put_dir_resp)
                     # continue
                     self.detail_deal_one_data(
                         goods_no=goods_no,
@@ -973,6 +960,13 @@ class RunMain:
                     config_data["success_handler"].append(
                         {"goods_art_no": goods_no, "success": True, "info": "处理成功"}
                     )
+                    detail_progress["folder"] = out_put_dir_resp
+                    self.sendAsyncMessage(
+                        msg="开始处理详情页",
+                        goods_arts=[],
+                        status="开始处理详情页",
+                        progress=detail_progress
+                    )
                     recordDataPoint(
                         token=self.token,
                         uuid=self.uuid,
@@ -980,6 +974,14 @@ class RunMain:
                         data={"goods_art_no": goods_no, "temp_name": _temp_name},
                     )
                 except BaseException as e:
+                    detail_error_progress+=1
+                    detail_progress = {"status":"处理失败","goods_art_no":goods_no, "current":detail_finish_progress, "total":detail_total_progress, "error":detail_error_progress,"folder":""}
+                    self.sendAsyncMessage(
+                        msg="处理失败",
+                        goods_arts=[],
+                        status="处理失败",
+                        progress=detail_progress
+                    )
                     self.show_progress_detail(
                         {
                             "goods_art_no": goods_no,
@@ -1025,132 +1027,23 @@ class RunMain:
         print("out_put_dir_resp", out_put_dir_resp)
         # 打开文件夹
         # os.startfile(out_put_dir)
-
+        detail_finish_progress = self.total_num - self.fail_num
+        text_status = "处理完成" if detail_finish_progress > 0 else "处理失败"
+        detail_progress = {
+            "status":text_status, 
+            "current":detail_finish_progress, 
+            "total":self.total_num, 
+            "error":self.fail_num,
+            "folder":out_put_dir_resp[0] if text_status=="处理完成" else "",
+        }
+        self.sendAsyncMessage(
+            msg=text_status,
+            goods_arts=[],
+            status=text_status,
+            progress=detail_progress
+        )
         return config_data
 
-    def detail_run_by_thread11111(
-        self,
-        config_data,
-        _goods_no_dict,
-        temp_name,
-        temp_name_list,
-        assigned_page_dict,
-        excel_temp_goods_no_data,
-        finally_goods_no_need_temps,
-    ):
-        """
-        excel_temp_goods_no_data: {},  # 表格数据可能存在多模板,数据结构为一个款号下的多个模板的数据列表
-        finally_goods_no_need_temps: {},  # 每个款号需要生成的模板数据
-        """
-
-        # 开始处理
-        self.n = 0
-        self.total_num = len(_goods_no_dict)
-        self.fail_num = 0
-        is_use_excel = config_data["is_use_excel"]
-        image_dir = config_data["image_dir"]
-
-        # 详情图生成结果文件夹
-        out_put_dir = "{}\软件-详情图生成".format(image_dir)
-        if settings.IS_TEST:
-            print("==============_goods_no_dict  打印=================")
-
-            print(json.dumps(_goods_no_dict))
-
-            print("==============_goods_no_dict  打印-end=================")
-
-        if settings.IS_TEST:
-            max_workers = 1
-        else:
-            max_workers = 1
-
-        all_detail_path_list = []
-
-        with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
-            futures = []
-            for goods_no, temp_name_list in finally_goods_no_need_temps.items():
-                for _temp_name in temp_name_list:
-                    # if _temp_name != "xiaosushuoxie-4":
-                    #     continue
-
-                    assigned_page_list = []
-                    if _temp_name in assigned_page_dict:
-                        assigned_page_list = assigned_page_dict[_temp_name]
-                    # 如果为使用表格,则获取表格中的数据作为款号的基础数据
-                    temp_info_data = copy.copy(_goods_no_dict[goods_no])
-                    if is_use_excel:
-                        # 将表格中的数据进行替换
-                        if goods_no in excel_temp_goods_no_data:
-                            if _temp_name in excel_temp_goods_no_data[goods_no]:
-                                # 将表格中的特定的模板的行,替换到goods_no的data中,因为不同的模板有数据特殊性
-                                print("xxxxxx====>", excel_temp_goods_no_data[goods_no])
-                                for _key, _key_value in excel_temp_goods_no_data[
-                                    goods_no
-                                ][_temp_name].items():
-                                    if _key in temp_info_data:
-                                        temp_info_data[_key] = _key_value
-
-                    print("temp_info_data11111111111111111111111")
-                    print("goods_no:{},_temp_name:{}".format(goods_no, _temp_name))
-                    all_detail_path_list.append(
-                        "{}/{}/".format(out_put_dir, _temp_name, goods_no)
-                    )
-                    # continue
-                    futures.append(
-                        executor.submit(
-                            self.detail_deal_one_data,
-                            goods_no=goods_no,
-                            value=temp_info_data,
-                            out_put_dir=out_put_dir,
-                            temp_name=_temp_name,
-                            assigned_page_list=assigned_page_list,
-                        )
-                    )
-
-            # for goods_no, value in _goods_no_dict.items():
-            #     _temp_name = temp_name
-            #     # 使用自定义的表格数据
-            #     if self.isUseTemplate is False:
-            #         if "模板名称" in value:
-            #             if value["模板名称"] in temp_name_list:
-            #                 _temp_name = value["模板名称"]
-            #     assigned_page_list = []
-            #     if _temp_name in assigned_page_dict:
-            #         assigned_page_list = assigned_page_dict[_temp_name]
-            #
-            #     futures.append(executor.submit(
-            #         self.deal_one_data,
-            #         goods_no=goods_no,
-            #         value=value,
-            #         out_put_dir=out_put_dir,
-            #         temp_name=_temp_name,
-            #         assigned_page_list=assigned_page_list,
-            #     ))
-
-            # 使用 wait 方法等待所有任务完成
-            done, not_done = concurrent.futures.wait(futures)
-
-            # 处理完成的任务
-            for future in done:
-                if settings.IS_TEST:
-                    result = future.result()
-
-        # ==============完成处理==============
-        self.set_state(state_value=2)
-        if self.total_num:
-            if self.fail_num:
-                self.show_progress_detail(
-                    "处理完成,-----------处理失败数据:{}个款".format(self.fail_num)
-                )
-            else:
-                self.show_progress_detail("处理完成")
-        else:
-            self.show_progress_detail("没有任何数据")
-
-        config_data["sign_text"] = "已结束详情处理"
-        config_data["all_detail_path_list"] = all_detail_path_list
-        self.run_end_sign.emit(config_data)
-
     def show_progress_detail(self, text):
         # self.show_progress_detail_sign.emit(text)
         # self.windows.show_progress_detail(text)
@@ -1178,6 +1071,11 @@ class RunMain:
         print("模板:", temp_name)
         print("value:", value)
         print("temp_class:", temp_class)
+        if temp_name not in temp_class or temp_class[temp_name] is None:
+            raise UnicornException(f"详情页模板 {temp_name} 未正确加载")
+            
+        if not callable(temp_class[temp_name]):
+            raise UnicornException(f"详情页模板 {temp_name} 不是有效的可调用对象")
         if settings.IS_TEST:
             temp_class[temp_name](
                 goods_no,

+ 21 - 33
python/settings.py

@@ -2,11 +2,12 @@ from wsgiref import headers
 from dotenv import load_dotenv, find_dotenv
 from pathlib import Path  # Python 3.6+ only
 import configparser, json, pytz
-import requests
+import requests,os
 import pillow_avif
 from utils.common import message_queue
 import hashlib
-
+from pathlib import Path
+import os,stat
 TIME_ZONE = pytz.timezone("Asia/Shanghai")
 from numpy import true_divide
 from databases import (
@@ -17,8 +18,10 @@ from databases import (
     batch_insert_sys_configs,
     SqlQuery,
     batch_insert_device_configs,
+    batch_insert_device_configsNew,
 )
-
+# 追加配置参数 machine_type 拍照机设备类型;0鞋;1服装
+MACHINE_TYPE = 0
 # 初始化数据表
 create_all_database()
 session = SqlQuery()
@@ -45,6 +48,7 @@ else:
             config = SysConfigs(**sys_config)
             session.add(config)
             session.commit()  # 合并事务提交
+session.close()
 # 初始化数据表---结束
 
 
@@ -63,6 +67,7 @@ def getSysConfigs(key, item, default=None):
     crud = CRUD(SysConfigs)
     one_item = crud.read(session, conditions={"key": key})
     config = json.loads(one_item.value)
+    session.close()
     if item == "image_out_format":
         default_format = config.get(item, default)
         if default_format == "" or default_format == None:
@@ -193,11 +198,11 @@ MOVE_DOWN = _mcu_config_dict["move_down"]
 STOP = _mcu_config_dict["stop"]
 
 
-camera_config_dict = config.items("camera_config")
-_camera_config_dict = {}
-for i, k in mcu_config_dict:
-    _camera_config_dict[i] = int(k)
-_camera_config_dict = get_config_by_items(camera_config_dict)
+# camera_config_dict = config.items("camera_config")
+# _camera_config_dict = {}
+# for i, k in mcu_config_dict:
+#     _camera_config_dict[i] = int(k)
+# _camera_config_dict = get_config_by_items(camera_config_dict)
 
 # LOW_ISO = _camera_config_dict["low_iso"]
 # HIGH_ISO = _camera_config_dict["high_iso"]
@@ -245,30 +250,6 @@ CUTOUT_MODE = (
 )
 import importlib
 
-# plugins = [
-#     # "custom_plugins.plugins.detail_template.huilima.detail_huilima1.DetailPicGet",
-#     ".custom_plugins.plugins.detail_template.huilima.detail_huilima1.DetailPicGet",
-#     # "custom_plugins.plugins.detail_template.huilima.detail_huilima2.DetailPicGet",
-#     # "custom_plugins.plugins.detail_template.huilima.detail_huilima3.DetailPicGet",
-#     # "custom_plugins.plugins.detail_template.huilima.detail_huilima4.DetailPicGet",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie1",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie2",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie3",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie4",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie5",
-#     # "custom_plugins.plugins.detail_template.xiaosushuoxie.detail_xiaosushuoxie6",
-#     # "custom_plugins.plugins.detail_template.hongqingting.detail_hongqingting1.DetailPicGet",
-#     # "custom_plugins.plugins_mode.detail_generate_base.DetailBase",
-#     # "custom_plugins.plugins_mode.pic_deal.PictureProcessing",
-# ]
-# def load_plugin(plugin_path):
-#     module_name, class_name = plugin_path.rsplit(".", 1)
-#     module = importlib.import_module(module_name)
-#     return getattr(module, class_name)
-
-
-# loaded_plugins = [load_plugin(p.lstrip(".")) for p in plugins]
-
 OUT_PIC_QUALITY = "普通"
 GRENERATE_MAIN_PIC_BRIGHTNESS = int(
     getSysConfigs("other_configs", "grenerate_main_pic_brightness", 254)
@@ -289,7 +270,7 @@ IMAGE_SAVE_MAX_WORKERS = int(
     getSysConfigs("other_configs", "image_save_max_workers", 20)
 )  # 批量保存的线程大小
 COLOR_GRADATION_CYCLES = int(
-    getSysConfigs("other_configs", "color_gradation_cycles", 22)
+    getSysConfigs("other_configs", "color_gradation_cycles", 23)
 )  # 色阶处理循环次数
 
 
@@ -340,3 +321,10 @@ def calculate_md5(filepath):
             md5hash.update(chunk)
         # 返回MD5哈希的十六进制表示
         return md5hash.hexdigest()
+__output_dir = config.get("output_config", "output_dir")
+path_obj = Path(os.path.abspath(__output_dir))
+OUTPUT_DIR = path_obj.absolute()
+print("OUTPUT_DIR",__output_dir,OUTPUT_DIR)
+def handle_remove_readonly(func, path, exc):
+    os.chmod(path, stat.S_IWRITE)
+    func(path)

+ 5 - 1
python/sockets/connect_manager.py

@@ -27,7 +27,11 @@ class ConnectionManager:
     async def send_personal_message(self, message: str, websocket: WebSocket):
         '''向用户发送消息'''
         # await websocket.send_json(message)
-        await websocket.send_json(message)
+        try:
+          await websocket.send_json(message)
+        except Exception as e:
+          logger.info(f"socket 消息发送异常:{str(e)}")
+          await asyncio.sleep(0.001)
 
     async def broadcast(self, message: str):
         """广播消息"""

+ 123 - 19
python/sockets/message_handler.py

@@ -16,7 +16,8 @@ import settings
 from middleware import UnicornException
 from concurrent.futures import ThreadPoolExecutor
 from functools import partial
-
+from logger import logger
+import stat
 # 创建全局线程池
 executor = ThreadPoolExecutor(max_workers=4)
 async def handlerCutOut(
@@ -52,7 +53,65 @@ async def handlerCutOut(
         )
         await manager.send_personal_message(data, websocket)
 
-
+def handlerFolderDelete(limit_path, goods_art_no_arrays, is_write_txt_log):
+    check_path(limit_path)
+    move_folder_array = check_move_goods_art_no_folder(
+        "output", goods_art_no_arrays, limit_path
+    )
+    
+    for goods_art_revice in goods_art_no_arrays:
+        cutout_goods = f"{limit_path}/{goods_art_revice}"
+        if os.path.exists(cutout_goods):
+            for root, dirs, files in os.walk(cutout_goods):
+                for file in files:
+                    filepath = os.path.join(root, file)
+                    os.chmod(filepath, stat.S_IWRITE)
+            logger.info(f"解除占用并开始删除目录:{cutout_goods}")
+            # 尝试多次删除,增加成功率
+            retry_count = 3
+            while retry_count > 0:
+                try:
+                    shutil.rmtree(cutout_goods, onerror=settings.handle_remove_readonly)
+                    del move_folder_array[goods_art_revice]
+                    break
+                except OSError as e:
+                    logger.info(f"目录已经被删除-OSError:{str(e)}")
+                    break
+                except (PermissionError) as e:
+                    retry_count -= 1
+                    if retry_count == 0:
+                        logger.info(f"抠图前目录删除出现问题-PermissionError:{str(e)};{goods_art_revice};{cutout_goods}")
+                        if is_write_txt_log:
+                            error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
+                            with open(error_file_path, 'w', encoding='utf-8') as f:
+                                f.write("目录删除失败\n")
+                                f.write(f"原因: 文件被占用或没有删除权限\n")
+                                f.write(f"错误信息: {str(e)}\n")
+                                f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
+                                f.write(f"请关闭可能正在使用此目录的程序后,为当前货号点击重拍后重试\n")
+                        else:
+                            raise UnicornException(f"目录检查出现问题:{str(e)},请关闭错误提示中的被占用文件")
+                    else:
+                        logger.info(f"抠图前目录删除出现问题--PermissionError:{str(e)};{retry_count}")
+                        time.sleep(0.5)  # 等待0.5秒后重试
+                except Exception as e:
+                    retry_count -= 1
+                    if retry_count == 0:
+                        logger.info(f"抠图前目录删除出现问题--Exception:{str(e)};{goods_art_revice};{cutout_goods}")
+                        if is_write_txt_log:
+                            error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
+                            with open(error_file_path, 'w', encoding='utf-8') as f:
+                                f.write("目录删除失败\n")
+                                f.write(f"原因: {str(e)}\n")
+                                f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
+                                f.write(f"请检查目录状态后,为当前货号点击重拍后重试\n")
+                        else:
+                            raise UnicornException(f"目录检查出现问题:{str(e)},请关闭错误提示中的被占用文件")
+                    else:
+                        logger.info(f"抠图前目录删除出现问题--Exception:{str(e)};{retry_count}")
+                        time.sleep(0.5)  # 等待0.5秒后重试
+    
+    return move_folder_array                
 # socket消息发送逻辑处理方法
 async def handlerSend(
     manager: ConnectionManager,
@@ -126,6 +185,9 @@ async def handlerSend(
                 device_ctrl.is_stop_action = True
             else:
                 print("动作没有执行,略过")
+                data = manager.jsonMessage(code=0, msg="执行终止", msg_type="run_mcu_stop")
+                await manager.send_personal_message(data, websocket)
+                return
         case "run_mcu":
             msg_type = "run_mcu"
             action_info = data.get("action", "执行左脚程序")
@@ -180,6 +242,7 @@ async def handlerSend(
                 ),
                 name="run_mcu_config",
             )
+            session.close()
         case "run_mcu_single":
             device_ctrl = DeviceControl(
                 websocket_manager=manager, smart_shooter=smart_shooter
@@ -198,8 +261,33 @@ async def handlerSend(
             blue_tooth = BlueToothMode(
                 websocket_manager=manager, smart_shooter=smart_shooter
             )
+            session = SqlQuery()
+            crud = CRUD(PhotoRecord)
+            record = crud.read(session=session, order_by="id", ascending=False)
+            if record == None:
+            # 发送失败消息
+                data = manager.jsonMessage(
+                            code=1,
+                            msg="单拍失败,请先输入货号或扫码进行组合拍摄",
+                            msg_type="handler_take_picture",
+                        )
+                await manager.send_personal_message(data, websocket)
+                return
+            try:
+                limit_path = "{}/{}".format(settings.OUTPUT_DIR,
+                    time.strftime("%Y-%m-%d", time.localtime(time.time()))
+                )
+                move_folder_array = handlerFolderDelete(limit_path,[record.goods_art_no],False)
+            except UnicornException as e:
+                data = manager.jsonMessage(
+                        code=1,
+                        msg=e.msg,
+                        msg_type="handler_take_picture",
+                    )
+                await manager.send_personal_message(data, websocket)
+                return
             loop.create_task(
-                blue_tooth.remote_control_v2.handlerTakePhoto(smart_shooter),
+                blue_tooth.remote_control_v2.handlerTakePhoto(smart_shooter,session,record),
                 name="run_mcu_config",
             )
             await asyncio.sleep(2.5)
@@ -248,6 +336,7 @@ async def handlerSend(
                 ),
                 name="run_mcu_config_single",
             )
+            session.close()
         case "get_deviation":
             device_ctrl = DeviceControl(
                 websocket_manager=manager, smart_shooter=smart_shooter
@@ -364,6 +453,20 @@ async def handlerSend(
             # 兼容主图测试
             id = data.get("id", 0)
             goods_art_no = data.get("goods_art_no", "")
+            if goods_art_no:
+                try:
+                    limit_path = "{}/{}".format(settings.OUTPUT_DIR,
+                        time.strftime("%Y-%m-%d", time.localtime(time.time()))
+                    )
+                    move_folder_array = handlerFolderDelete(limit_path,[goods_art_no],False)
+                except UnicornException as e:
+                    data = manager.jsonMessage(
+                            code=1,
+                            msg=e.msg,
+                            msg_type="smart_shooter_photo_take",
+                        )
+                    await manager.send_personal_message(data, websocket)
+                    return
             is_af = True
             loop.create_task(
                 smart_shooter.CameraShooter(
@@ -393,7 +496,7 @@ async def handlerSend(
                 return
             reset_data = {"image_path": None}
             photoRecord.update(session, id, **reset_data)
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(websocket_manager=manager)#
             loop.create_task(
                 device_ctrl.only_take_photo(
                     goods_art_no=goods_art_no,
@@ -402,6 +505,7 @@ async def handlerSend(
                 ),
                 name="sendCommand",
             )
+            session.close()
         case "segment_progress":
             msg_type = "segment_progress"
             obj = None
@@ -410,29 +514,28 @@ async def handlerSend(
             uuid = data.get("uuid", "")
             run_main = RunMain(obj, token, uuid)
             goods_art_no_arrays = data.get("goods_art_no", [])
-            limit_path = "output/{}".format(
+            limit_path = "{}/{}".format(settings.OUTPUT_DIR,
                 time.strftime("%Y-%m-%d", time.localtime(time.time()))
             )
-            check_path(limit_path)
+            try:
+                move_folder_array = handlerFolderDelete(limit_path,goods_art_no_arrays,True)
+            except UnicornException as e:
+                data = manager.jsonMessage(
+                        code=1,
+                        msg=e.msg,
+                        msg_type=msg_type,
+                    )
+                await manager.send_personal_message(data, websocket)
+                return
             # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
-            move_folder_array = check_move_goods_art_no_folder(
-                "output", goods_art_no_arrays, limit_path
-            )
-            for goods_art_revice in goods_art_no_arrays:
-                cutout_goods = f"{limit_path}/{goods_art_revice}"
-                if os.path.exists(cutout_goods):
-                    # 寻找当前被扣图的货号在现有目录中是否存在,如果存在先删除
-                    # 重新执行抠图操作
-                    shutil.rmtree(cutout_goods)
-                    del move_folder_array[goods_art_revice]
+            session = SqlQuery()
             for goods_art_no in goods_art_no_arrays:
-                session = SqlQuery()
                 pr = CRUD(PhotoRecord)
                 images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
                 if not images:
                     data = manager.jsonMessage(
                         code=1,
-                        msg=f"没有可用货号数据",
+                        msg=f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确",
                         msg_type=msg_type,
                     )
                     await manager.send_personal_message(data, websocket)
@@ -450,7 +553,7 @@ async def handlerSend(
                             await manager.send_personal_message(data, websocket)
                             return
                         new_file_name = (
-                            str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
+                            str(idx)+"_"+str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
                         )
                         if not os.path.exists(
                             image_dir + "/" + os.path.basename(new_file_name)
@@ -471,6 +574,7 @@ async def handlerSend(
                         )
                         await manager.send_personal_message(data, websocket)
                         return
+            session.close()
             # try:
             cutOutMode = (
                 "1"

+ 1 - 1
python/sockets/socket_server.py

@@ -35,7 +35,7 @@ async def updateDataRecord(PhotoFilename, id):
         # 走编辑逻辑
         record_model.updateConditions(session, conditions={"id": id}, **data)
         print(f"smart shooter 拍照记录更新成功,记录id:{id}")
-
+    session.close()
 
 @app.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket):

+ 26 - 6
python/temp.py

@@ -1,6 +1,26 @@
-from PIL import Image
-path = "output/2025-09-11/NSK002/阴影图处理/NSK002(3)_后跟_抠图.png"
-img = Image.open(path)
-imgBg = Image.new("RGB", img.size,(255,255,255))
-imgBg.paste(img, (0, 0), img)  # 修复:不再将paste()的结果赋值给img
-imgBg.show()  # 修复:显示imgBg而不是img
+# from PIL import Image
+# from settings import recordDataPoint
+import time
+from service.online_request.module_online_data import OnlineDataRequest,AIGCDataRequest
+aigc = AIGCDataRequest("Bearer f99e72d818b504d23e0581ef1b1a2b4bb687c683")
+# status, result_image = aigc.searchProgress(1127984)
+# print(status,result_image)
+search_times = 60
+while search_times > 0:
+            print(f"模特图查询第{search_times}次")
+            # logger.info(f"模特图查询第{search_times}次")
+            status, result_image = aigc.searchProgress(1127989)
+            # status: -1=失败, 0=排队中, 1=进行中, 2=完成
+            if status == 2:  # 完成
+                break
+            if status == -1:  # 失败
+                break
+            # status为0(排队中)或1(进行中)时继续查询
+            time.sleep(1)
+            search_times -= 1
+        # 循环结束后检查最终状态
+if status == -1 or (status != 2 and search_times <= 0):
+    print("模特图生成失败")
+    exit()
+# save_image_path = download_image_with_pil(result_image, save_path)
+print("上脚图save_image_path",result_image)

Some files were not shown because too many files changed in this diff