|
|
@@ -1,4 +1,4 @@
|
|
|
-from re import search
|
|
|
+from re import search,match
|
|
|
from natsort.natsort import order_by_index
|
|
|
from sqlalchemy import func
|
|
|
from models import *
|
|
|
@@ -35,6 +35,8 @@ import functools
|
|
|
import traceback,stat
|
|
|
import concurrent.futures
|
|
|
from sockets.message_handler import handlerFolderDelete
|
|
|
+from service.remove_bg_ali import RemoveBgALi
|
|
|
+import uuid as mine_uuid
|
|
|
def log_exception_with_context(context_message=""):
|
|
|
"""装饰器:为函数添加异常日志上下文"""
|
|
|
|
|
|
@@ -142,27 +144,28 @@ async def forwardRequest(request: HlmForwardRequest):
|
|
|
|
|
|
def __createExcelGoodsArray(excel_path):
|
|
|
'''创建通过excel形式得货号组数据'''
|
|
|
- excel_df = pd.read_excel(excel_path, sheet_name=0, header=0)
|
|
|
- if "文件夹名称" not in excel_df.columns:
|
|
|
- raise UnicornException("缺失 [文件夹名称] 列")
|
|
|
- if "商品货号" not in excel_df.columns:
|
|
|
- raise UnicornException("缺失 [商品货号] 列")
|
|
|
- if "款号" not in excel_df.columns:
|
|
|
- raise UnicornException("缺失 [款号] 列")
|
|
|
- goods_art_dirs = excel_df.groupby(excel_df["款号"])
|
|
|
- # 抠图时用到的货号列表,与生成详情图有所区别
|
|
|
- goods_art_no_arrays = []
|
|
|
- # # 详情图生成需要对同款商品进行分组,保证详情图可以生成多个色
|
|
|
- goods_art_no_group_arrays = []
|
|
|
- for _, goods_row in excel_df.iterrows():
|
|
|
- goods_art_no = str(goods_row["商品货号"])
|
|
|
- goods_art_no_arrays.append(goods_art_no)
|
|
|
- goods_no = str(goods_row["款号"])
|
|
|
- a001_df = goods_art_dirs.get_group(goods_no)
|
|
|
- goods_art_groups = a001_df["商品货号"].tolist()
|
|
|
- if goods_art_groups in goods_art_no_group_arrays:
|
|
|
- continue
|
|
|
- goods_art_no_group_arrays.append(goods_art_groups)
|
|
|
+ try:
|
|
|
+ excel_df = pd.read_excel(excel_path, sheet_name=0, header=0)
|
|
|
+ if "商品货号" not in excel_df.columns:
|
|
|
+ raise UnicornException("缺失 [商品货号] 列")
|
|
|
+ if "款号" not in excel_df.columns:
|
|
|
+ raise UnicornException("缺失 [款号] 列")
|
|
|
+ goods_art_dirs = excel_df.groupby(excel_df["款号"])
|
|
|
+ # 抠图时用到的货号列表,与生成详情图有所区别
|
|
|
+ goods_art_no_arrays = []
|
|
|
+ # # 详情图生成需要对同款商品进行分组,保证详情图可以生成多个色
|
|
|
+ goods_art_no_group_arrays = []
|
|
|
+ for _, goods_row in excel_df.iterrows():
|
|
|
+ goods_art_no = str(goods_row["商品货号"])
|
|
|
+ goods_art_no_arrays.append(goods_art_no)
|
|
|
+ goods_no = str(goods_row["款号"])
|
|
|
+ a001_df = goods_art_dirs.get_group(goods_no)
|
|
|
+ goods_art_groups = a001_df["商品货号"].tolist()
|
|
|
+ if goods_art_groups in goods_art_no_group_arrays:
|
|
|
+ continue
|
|
|
+ goods_art_no_group_arrays.append(goods_art_groups)
|
|
|
+ except Exception as e:
|
|
|
+ raise UnicornException("Excel文件解析失败,请检查是否缺少列")
|
|
|
return goods_art_no_arrays,excel_df,goods_art_no_group_arrays
|
|
|
|
|
|
|
|
|
@@ -247,7 +250,6 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
|
|
|
# 初始化基础变量
|
|
|
handler_result = []
|
|
|
handler_result_folder = ""
|
|
|
-
|
|
|
# 处理参数
|
|
|
obj, token, uuid = None, "Bearer " + params.token, params.uuid
|
|
|
aigc_clazz = AIGCDataRequest(token)
|
|
|
@@ -284,14 +286,12 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
|
|
|
handler_result_folder, handler_result = await _process_cutout(
|
|
|
run_main, config_data, goods_art_no_arrays, move_folder_array
|
|
|
)
|
|
|
-
|
|
|
# 处理场景图和模特图
|
|
|
- return_data_check_before_detail = run_main.check_before_detail(config_data)
|
|
|
+ return_data_check_before_detail = run_main.check_before_detail(config_data,is_detail)
|
|
|
|
|
|
# 检查处理结果
|
|
|
success_handler = return_data_check_before_detail.get("data", {}).get("config_data", {}).get("success_handler", [])
|
|
|
failed_items = [item for item in success_handler if item.get('success') == False]
|
|
|
-
|
|
|
if failed_items:
|
|
|
await sendAsyncMessage(
|
|
|
msg="处理结束",
|
|
|
@@ -334,7 +334,8 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
|
|
|
if is_detail == 1:
|
|
|
handler_result_folder, handler_result= await _process_detail_pages(
|
|
|
run_main, return_data_check_before_detail, onlineData,
|
|
|
- online_stores, goods_art_no_arrays, handler_result_folder
|
|
|
+ online_stores, goods_art_no_arrays, handler_result_folder,
|
|
|
+ params
|
|
|
)
|
|
|
# 如果需要上传到第三方平台
|
|
|
if online_stores:
|
|
|
@@ -351,7 +352,7 @@ async def process_handle_detail(request: Request, params: HandlerDetail):
|
|
|
else:
|
|
|
await sendAsyncMessage(
|
|
|
msg="处理结束",
|
|
|
- data={"output_folder": f"{handler_result_folder}/{current_day}", "list": handler_result},
|
|
|
+ data={"output_folder": f"{handler_result_folder}", "list": handler_result},
|
|
|
status="处理结束",
|
|
|
msg_type="detail_result_progress",
|
|
|
)
|
|
|
@@ -382,7 +383,7 @@ async def _process_non_excel_mode(params, goods_art_no_arrays):
|
|
|
|
|
|
session = SqlQuery()
|
|
|
pr = CRUD(PhotoRecord)
|
|
|
- images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
|
|
|
+ images = pr.read_all(session, conditions={"goods_art_no": goods_art_no,"delete_time": None})
|
|
|
session.close()
|
|
|
if not images:
|
|
|
raise UnicornException(
|
|
|
@@ -408,20 +409,19 @@ async def _process_excel_mode(goods_art_no_arrays,excel_df):
|
|
|
move_folder_array = check_move_goods_art_no_folder("output", goods_art_no_arrays, limit_path)
|
|
|
session = SqlQuery()
|
|
|
for index, row in excel_df.iterrows():
|
|
|
- goods_art_no_image_dir = str(row["文件夹名称"])
|
|
|
goods_art_no = str(row["商品货号"])
|
|
|
print("货号数据", goods_art_no)
|
|
|
if not goods_art_no:
|
|
|
raise UnicornException("货号不能为空")
|
|
|
pr = CRUD(PhotoRecord)
|
|
|
- images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
|
|
|
+ images = pr.read_all(session, conditions={"goods_art_no": goods_art_no,"delete_time": None})
|
|
|
if not images:
|
|
|
raise UnicornException(
|
|
|
f"商品货号【{goods_art_no}】未查询到拍摄记录,请检查表格中的货号数据列"
|
|
|
)
|
|
|
# 货号目录不存在再去进行移动和创建操作
|
|
|
if move_folder_array.get(goods_art_no) is None:
|
|
|
- await _process_image_copy_and_move(goods_art_no_image_dir, images,True)
|
|
|
+ await _process_image_copy_and_move(goods_art_no, images,True)
|
|
|
session.close()
|
|
|
return move_folder_array
|
|
|
|
|
|
@@ -457,9 +457,9 @@ async def _build_config_data(params, goods_art_no_arrays):
|
|
|
"""构建配置数据"""
|
|
|
temp_class = {}
|
|
|
temp_name_list = []
|
|
|
-
|
|
|
+ # 模板类型;0系统模板;1自定义模板
|
|
|
for tempItem in params.temp_list:
|
|
|
- temp_class[tempItem.template_id] = tempItem.template_local_classes
|
|
|
+ temp_class[tempItem.template_id] = {"class_path":tempItem.template_local_classes,"template_type":tempItem.template_type if tempItem.template_type else 0}
|
|
|
temp_name_list.append(tempItem.template_id)
|
|
|
|
|
|
cutOutMode = (
|
|
|
@@ -473,7 +473,7 @@ async def _build_config_data(params, goods_art_no_arrays):
|
|
|
config_data = {
|
|
|
"image_dir": limit_path,
|
|
|
"image_order": (
|
|
|
- "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5"
|
|
|
+ "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5,组合6,组合7,组合8,组合9,组合10,组合11,组合12,组合13,组合14,组合15,组合16,组合17,组合18,组合19,组合20,组合21,组合22,组合23,组合24,组合25,组合26"
|
|
|
if not params.template_image_order
|
|
|
else params.template_image_order
|
|
|
),
|
|
|
@@ -499,18 +499,22 @@ async def _build_config_data(params, goods_art_no_arrays):
|
|
|
"target_error_folder": f"{limit_path}/软件-生成详情错误",
|
|
|
"success_handler": [],
|
|
|
}
|
|
|
-
|
|
|
- # 动态导入类
|
|
|
+ temp_class_dict = {}
|
|
|
try:
|
|
|
- temp_class_dict = {}
|
|
|
- for key, class_path in config_data["temp_class"].items():
|
|
|
- module_path, class_name = class_path.rsplit(".", 1)
|
|
|
- module = importlib.import_module(module_path)
|
|
|
- cls = getattr(module, class_name)
|
|
|
- temp_class_dict[key] = cls
|
|
|
+ print("configdata 模板信息",config_data["temp_class"])
|
|
|
+ for key, val in config_data["temp_class"].items():
|
|
|
+ class_path = val.get("class_path")
|
|
|
+ template_type = val.get("template_type",0)
|
|
|
+ if template_type == 0:
|
|
|
+ # 如果是系统模板,才进行动态类导入操作
|
|
|
+ module_path, class_name = class_path.rsplit(".", 1)
|
|
|
+ module = importlib.import_module(module_path)
|
|
|
+ cls = getattr(module, class_name)
|
|
|
+ temp_class_dict[key] = {"cls":cls,"template_type":template_type}
|
|
|
+ else:
|
|
|
+ temp_class_dict[key] = {"cls":class_path,"template_type":template_type}
|
|
|
except:
|
|
|
- raise UnicornException("详情页模板不存在或未下载完成,请重启软件后重试")
|
|
|
-
|
|
|
+ raise UnicornException("详情页模板不存在或未下载完成,请重启软件后重试")
|
|
|
config_data["temp_class"] = temp_class_dict
|
|
|
return config_data
|
|
|
|
|
|
@@ -518,10 +522,24 @@ async def _process_cutout(run_main, config_data, goods_art_no_arrays, move_folde
|
|
|
"""处理抠图"""
|
|
|
handler_result = []
|
|
|
handler_result_folder = ""
|
|
|
-
|
|
|
+ have_handler_keys = move_folder_array.keys()
|
|
|
+ if len(have_handler_keys) >0 :
|
|
|
+ progress = {
|
|
|
+ "status":"正在处理",
|
|
|
+ "current":len(have_handler_keys),
|
|
|
+ "total":len(goods_art_no_arrays),
|
|
|
+ "error":0,
|
|
|
+ "goods_art_no":None
|
|
|
+ }
|
|
|
+ await sendAsyncMessage(
|
|
|
+ msg="正在处理",
|
|
|
+ data=None,
|
|
|
+ status="正在处理",
|
|
|
+ msg_type="segment_progress",
|
|
|
+ progress=progress
|
|
|
+ )
|
|
|
return_data = run_main.check_before_cutout(config_data)
|
|
|
cutout_res = run_main.check_for_cutout_image_first_call_back(return_data)
|
|
|
-
|
|
|
if cutout_res:
|
|
|
# sys_path = format(os.getcwd()).replace("\\", "/")
|
|
|
handler_result_folder = f"{config_data['image_dir']}"
|
|
|
@@ -533,7 +551,7 @@ async def _process_cutout(run_main, config_data, goods_art_no_arrays, move_folde
|
|
|
"info": "处理成功",
|
|
|
})
|
|
|
|
|
|
- if len(move_folder_array.keys()) == len(goods_art_no_arrays):
|
|
|
+ if len(have_handler_keys) == len(goods_art_no_arrays) or (len(have_handler_keys) == 0 and cutout_res):
|
|
|
handler_result_folder = handler_result_folder.replace("\\", "/")
|
|
|
success_items = [item for item in handler_result if item.get('success') == True]
|
|
|
cutout_folder = handler_result_folder+"/"+success_items[0].get("goods_art_no")+"/800x800" if len(success_items) > 0 else ""
|
|
|
@@ -551,7 +569,6 @@ async def _process_cutout(run_main, config_data, goods_art_no_arrays, move_folde
|
|
|
msg_type="segment_progress",
|
|
|
progress=progress
|
|
|
)
|
|
|
-
|
|
|
return handler_result_folder, handler_result
|
|
|
|
|
|
async def _process_scene_images(aigc_clazz, run_main, return_data_check_before_detail, product_scene_prompt):
|
|
|
@@ -719,7 +736,7 @@ async def _process_model_images(aigc_clazz, run_main, return_data_check_before_d
|
|
|
msg_type="upper_footer_progress",
|
|
|
progress=upper_footer_progress
|
|
|
)
|
|
|
-
|
|
|
+ print("上脚图=====>>>>",goods_dict,return_data_check_before_detail)
|
|
|
for goods_art_no_info in goods_dict.keys():
|
|
|
goods_art_dict_info = goods_dict.get(goods_art_no_info,None)
|
|
|
new_goods_dict.setdefault(goods_art_no_info,goods_art_dict_info)
|
|
|
@@ -783,6 +800,7 @@ async def _process_model_images(aigc_clazz, run_main, return_data_check_before_d
|
|
|
)
|
|
|
|
|
|
except (concurrent.futures.TimeoutError, Exception) as e:
|
|
|
+ print("模特图处理异常信息",e)
|
|
|
os.remove(save_image_path)
|
|
|
# upper_footer_finish_progress-=1
|
|
|
upper_footer_error_progress += 1
|
|
|
@@ -826,15 +844,15 @@ async def _process_model_images(aigc_clazz, run_main, return_data_check_before_d
|
|
|
return return_data_check_before_detail
|
|
|
|
|
|
async def _process_detail_pages(run_main, return_data_check_before_detail, onlineData,
|
|
|
- online_stores, goods_art_no_arrays, handler_result_folder):
|
|
|
+ online_stores, goods_art_no_arrays, handler_result_folder,request_params):
|
|
|
"""处理详情页生成和上传"""
|
|
|
check_for_detail_first_res = run_main.check_for_detail_first_call_back(
|
|
|
- return_data_check_before_detail
|
|
|
+ return_data_check_before_detail,request_params
|
|
|
)
|
|
|
print("<======>check_for_detail_first_res<======>",check_for_detail_first_res)
|
|
|
if isinstance(check_for_detail_first_res, partial):
|
|
|
- result = check_for_detail_first_res()
|
|
|
try:
|
|
|
+ result = check_for_detail_first_res()
|
|
|
config_data = result["config_data"]
|
|
|
except:
|
|
|
config_data = result
|
|
|
@@ -984,7 +1002,7 @@ def device_config_detail(params: ModelGetDeviceConfigDetail):
|
|
|
model = configModel.read(session, conditions={"id": action_id})
|
|
|
session.close()
|
|
|
if model == None:
|
|
|
- return {"code": 1, "msg": "数据不存在", "data": None}
|
|
|
+ return {"code": 1, "msg": "相关配置不存在,请删除当前货号后重新拍摄", "data": None}
|
|
|
return {"code": 0, "msg": "", "data": model}
|
|
|
|
|
|
|
|
|
@@ -1070,45 +1088,86 @@ def reset_config(params: ModelGetDeviceConfig):
|
|
|
@app.get("/get_photo_records", description="获取拍照记录")
|
|
|
def get_photo_records(page: int = 1, size: int = 5):
|
|
|
session = SqlQuery()
|
|
|
+ current_page = page
|
|
|
# photos = CRUD(PhotoRecord)
|
|
|
print("准备查询拍摄记录", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
|
- statement = (
|
|
|
- select(PhotoRecord)
|
|
|
+
|
|
|
+ # 首先统计总数
|
|
|
+ count_statement = (
|
|
|
+ select(func.count(PhotoRecord.goods_art_no.distinct()))
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
+ )
|
|
|
+ total_count = session.exec(count_statement).one()
|
|
|
+
|
|
|
+ # 查询所有不重复的货号及对应的最大时间,进行分页
|
|
|
+ base_statement = (
|
|
|
+ select(PhotoRecord.goods_art_no, func.max(PhotoRecord.id).label('max_id'))
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
+ .group_by(PhotoRecord.goods_art_no)
|
|
|
+ .order_by(desc('max_id'))
|
|
|
.offset((page - 1) * size)
|
|
|
.limit(size)
|
|
|
- .order_by(desc("id"))
|
|
|
- .group_by("goods_art_no")
|
|
|
)
|
|
|
- list = []
|
|
|
- result = session.exec(statement).all()
|
|
|
- print("group 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
|
- join_conditions = [
|
|
|
- {
|
|
|
- "model": DeviceConfig,
|
|
|
- "on": PhotoRecord.action_id == DeviceConfig.id,
|
|
|
- "is_outer": False, # 可选,默认False,设为True则为LEFT JOIN
|
|
|
- }
|
|
|
- ]
|
|
|
- for item in result:
|
|
|
+ paginated_results = session.exec(base_statement).all()
|
|
|
+
|
|
|
+ # 获取这些货号的详细记录
|
|
|
+ list_data = []
|
|
|
+ if paginated_results:
|
|
|
+ # 获取当前页的货号列表
|
|
|
+ current_goods_art_nos = [item.goods_art_no for item in paginated_results]
|
|
|
+
|
|
|
+ # 查询这些货号的所有记录
|
|
|
query = (
|
|
|
select(PhotoRecord, DeviceConfig.action_name)
|
|
|
- .where(PhotoRecord.goods_art_no == item.goods_art_no)
|
|
|
- .join(DeviceConfig, PhotoRecord.action_id == DeviceConfig.id)
|
|
|
- )
|
|
|
- list_item = session.exec(query).mappings().all()
|
|
|
- list.append(
|
|
|
- {
|
|
|
- "goods_art_no": item.goods_art_no,
|
|
|
- "action_time": item.create_time,
|
|
|
- "items": list_item,
|
|
|
- }
|
|
|
+ .outerjoin(DeviceConfig, PhotoRecord.action_id == DeviceConfig.id)
|
|
|
+ .where(PhotoRecord.goods_art_no.in_(current_goods_art_nos))
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
+ .order_by(asc("image_index")) # 按货号分组并按ID倒序
|
|
|
)
|
|
|
+ all_items = session.exec(query).mappings().all()
|
|
|
+
|
|
|
+ # 按货号分组
|
|
|
+ items_by_goods = {}
|
|
|
+ for item in all_items:
|
|
|
+ goods_art_no = item.PhotoRecord.goods_art_no
|
|
|
+ if goods_art_no not in items_by_goods:
|
|
|
+ items_by_goods[goods_art_no] = []
|
|
|
+ items_by_goods[goods_art_no].append(item)
|
|
|
+
|
|
|
+ # 构建结果列表,保持分页的顺序
|
|
|
+ for item in paginated_results:
|
|
|
+ goods_art_no = item.goods_art_no
|
|
|
+ if goods_art_no in items_by_goods:
|
|
|
+ # 获取该货号下时间最新的记录作为action_time
|
|
|
+ latest_record = items_by_goods[goods_art_no][0].PhotoRecord
|
|
|
+ list_data.append(
|
|
|
+ {
|
|
|
+ "goods_art_no": goods_art_no,
|
|
|
+ "action_time": latest_record.create_time,
|
|
|
+ "items": items_by_goods[goods_art_no],
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
session.close()
|
|
|
print("循环查询 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
|
+
|
|
|
+ # 计算分页信息
|
|
|
+ total_pages = (total_count + size - 1) // size # 向上取整
|
|
|
+ has_prev = page > 1
|
|
|
+ has_next = page < total_pages
|
|
|
+
|
|
|
return {
|
|
|
"code": 0,
|
|
|
"msg": "",
|
|
|
- "data": {"list": list, "page": page, "size": size},
|
|
|
+ "data": {
|
|
|
+ "list": list_data,
|
|
|
+ "current_page": current_page,
|
|
|
+ "size": size,
|
|
|
+ "total_count": total_count,
|
|
|
+ "total_pages": total_pages,
|
|
|
+ "has_prev": has_prev,
|
|
|
+ "has_next": has_next
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1118,6 +1177,7 @@ def get_last_photo_record():
|
|
|
statement = (
|
|
|
select(PhotoRecord)
|
|
|
.where(PhotoRecord.image_path != None)
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
.order_by(desc("photo_create_time"))
|
|
|
)
|
|
|
result = session.exec(statement).first()
|
|
|
@@ -1135,7 +1195,7 @@ def get_photo_record_detail(goods_art_no: str = None):
|
|
|
return {"code": 1, "msg": "参数错误", "data": None}
|
|
|
session = SqlQuery()
|
|
|
photos = CRUD(PhotoRecord)
|
|
|
- items = photos.read_all(session, conditions={"goods_art_no": goods_art_no})
|
|
|
+ items = photos.read_all(session, conditions={"goods_art_no": goods_art_no,"delete_time": None})
|
|
|
session.close()
|
|
|
return {
|
|
|
"code": 0,
|
|
|
@@ -1153,7 +1213,8 @@ def delect_goods_arts(params: PhotoRecordDelete):
|
|
|
session = SqlQuery()
|
|
|
photos = CRUD(PhotoRecord)
|
|
|
for item in params.goods_art_nos:
|
|
|
- photos.deleteConditions(session, conditions={"goods_art_no": item})
|
|
|
+ settings.syncPhotoRecord({"goods_art_no": item},action_type=2)
|
|
|
+ photos.deleteConditions(session, conditions={"goods_art_no": item,"delete_time": None})
|
|
|
session.close()
|
|
|
return {
|
|
|
"code": 0,
|
|
|
@@ -1233,7 +1294,7 @@ def update_left_right_config(params: LeftRightParams):
|
|
|
def update_record(params: RecordUpdate):
|
|
|
session = SqlQuery()
|
|
|
photoRecord = CRUD(PhotoRecord)
|
|
|
- model = photoRecord.read(session, conditions={"id": params.id})
|
|
|
+ model = photoRecord.read(session, conditions={"id": params.id,"delete_time": None})
|
|
|
if model == None:
|
|
|
return {"code": 1, "msg": "记录不存在", "data": None}
|
|
|
kwargs = params.__dict__
|
|
|
@@ -1377,12 +1438,15 @@ def syncUserJsonConfigs(token):
|
|
|
@app.post("/sync_sys_configs", description="同步线上配置到本地")
|
|
|
def sync_sys_configs(params: SyncLocalConfigs):
|
|
|
hlm_token = params.token
|
|
|
+ env = params.env
|
|
|
+ settings.USER_TOKEN = hlm_token
|
|
|
+ settings.USER_ENV = env
|
|
|
headers = {
|
|
|
"Authorization": f"Bearer {hlm_token}",
|
|
|
"content-type": "application/json",
|
|
|
}
|
|
|
# 追加配置参数 machine_type 拍照机设备类型;0鞋;1服装
|
|
|
- url = settings.DOMAIN + f"/api/ai_image/camera_machine/get_all_user_configs?machine_type={MACHINE_TYPE}"
|
|
|
+ url = settings.getDoman(env) + f"/api/ai_image/camera_machine/get_all_user_configs?machine_type={MACHINE_TYPE}"
|
|
|
result = requests.get(url=url, headers=headers)
|
|
|
print("result",result.json())
|
|
|
sys_configs = result.json().get("data", {}).get("configs")
|
|
|
@@ -1416,11 +1480,14 @@ def sync_sys_configs(params: SyncLocalConfigs):
|
|
|
@app.post("/sync_actions", description="同步左右脚配置到本地")
|
|
|
def sync_action_configs(params: SyncLocalConfigs):
|
|
|
hlm_token = params.token
|
|
|
+ env = params.env
|
|
|
+ settings.USER_TOKEN = hlm_token
|
|
|
+ settings.USER_ENV = env
|
|
|
headers = {
|
|
|
"Authorization": f"Bearer {hlm_token}",
|
|
|
"content-type": "application/json",
|
|
|
}
|
|
|
- url = settings.DOMAIN + f"/api/ai_image/camera_machine/get_all_user_tabs?machine_type={MACHINE_TYPE}"
|
|
|
+ url = settings.getDoman(env) + f"/api/ai_image/camera_machine/get_all_user_tabs?machine_type={MACHINE_TYPE}"
|
|
|
result = requests.get(url=url, headers=headers)
|
|
|
session = SqlQuery()
|
|
|
deviceConfigs = CRUD(DeviceConfig)
|
|
|
@@ -1430,7 +1497,7 @@ def sync_action_configs(params: SyncLocalConfigs):
|
|
|
if tabs:
|
|
|
# 先删除再创建
|
|
|
deviceConfigTabs.deleteConditions(session, {})
|
|
|
- deviceConfigs.deleteConditions(session, {})
|
|
|
+ deviceConfigs.deleteConditions(session, {},False)
|
|
|
batch_insert_device_configsNew(session, tabs, actions)
|
|
|
else:
|
|
|
all_actions = deviceConfigs.read_all(session)
|
|
|
@@ -1462,3 +1529,304 @@ def sync_action_configs(params: SyncLocalConfigs):
|
|
|
# syncUserJsonConfigs(hlm_token)
|
|
|
session.close()
|
|
|
return {"code": 0, "msg": "操作成功", "data": None}
|
|
|
+
|
|
|
+@app.get("/get_goods_image_json", description="关闭窗口")
|
|
|
+def get_goods_image_json(goods_art_no: str,token:str):
|
|
|
+ remove_pic_ins = RemoveBgALi()
|
|
|
+ if goods_art_no == None or goods_art_no == "":
|
|
|
+ # 判断货号是否存在
|
|
|
+ raise UnicornException("货号不能为空")
|
|
|
+ session = SqlQuery()
|
|
|
+ photoRecord = CRUD(PhotoRecord)
|
|
|
+ goods_art_record = photoRecord.read_all(
|
|
|
+ session, conditions={"goods_art_no": goods_art_no,"delete_time": None}
|
|
|
+ )
|
|
|
+ if not goods_art_record:
|
|
|
+ raise UnicornException("该货号拍摄记录不存在")
|
|
|
+ action_id_array = [record.action_id for record in goods_art_record]
|
|
|
+ devices = CRUD(DeviceConfig)
|
|
|
+ devices_record = devices.read_all(session,conditions={"id": action_id_array})
|
|
|
+ # 提取 action_name 字段并拼接
|
|
|
+ action_names = [str(record.action_name) for record in devices_record]
|
|
|
+ action_names_str = ",".join(action_names)
|
|
|
+ image_arrays = []
|
|
|
+ for goods_art_record_item in goods_art_record:
|
|
|
+ image_path = goods_art_record_item.image_path
|
|
|
+ try:
|
|
|
+ image_url = uploadImage(remove_pic_ins=remove_pic_ins,token=token, local_path=image_path)
|
|
|
+ except Exception as e:
|
|
|
+ raise UnicornException("网络异常,请重试")
|
|
|
+ image_arrays.append(image_url)
|
|
|
+ session.close()
|
|
|
+ return {"code": 0, "msg": "关闭失败", "data": {"customer_template_images": image_arrays,"template_image_order":action_names_str}}
|
|
|
+def uploadImage(remove_pic_ins,token:str, local_path: str) -> str:
|
|
|
+ im = remove_pic_ins.get_image_cut_new(file_path=local_path)
|
|
|
+ post_headers = {"Authorization": "Bearer " +token}
|
|
|
+ url = settings.DOMAIN + "/api/upload"
|
|
|
+ resultData = requests.post(
|
|
|
+ url, files={"file":im}, headers=post_headers
|
|
|
+ ).json()
|
|
|
+ return resultData["data"]["url"]
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+@app.post("/remove_background", description="图片抠图-http请求")
|
|
|
+async def remove_background(params:PhotoRecordRemoveBackground):
|
|
|
+ # await socket_manager.send_message(msg="测试")
|
|
|
+ executor = ThreadPoolExecutor(max_workers=4)
|
|
|
+ obj = None
|
|
|
+ token = params.token
|
|
|
+ token = "Bearer " + token
|
|
|
+ uuid = mine_uuid.uuid4().hex
|
|
|
+ run_main = RunMain(obj, token, uuid)
|
|
|
+ goods_art_no_arrays = params.goods_art_nos
|
|
|
+ limit_path = "{}/{}".format(settings.OUTPUT_DIR,
|
|
|
+ time.strftime("%Y-%m-%d", time.localtime(time.time()))
|
|
|
+ )
|
|
|
+ try:
|
|
|
+ move_folder_array = handlerFolderDelete(limit_path,goods_art_no_arrays,True)
|
|
|
+ except UnicornException as e:
|
|
|
+ raise UnicornException(e.msg)
|
|
|
+ # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
|
|
|
+ session = SqlQuery()
|
|
|
+ for goods_art_no in goods_art_no_arrays:
|
|
|
+ pr = CRUD(PhotoRecord)
|
|
|
+ images = pr.read_all(session, conditions={"goods_art_no": goods_art_no,"delete_time": None})
|
|
|
+ if not images:
|
|
|
+ raise UnicornException(f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确")
|
|
|
+ if move_folder_array.get(goods_art_no) == None:
|
|
|
+ image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
|
|
|
+ check_path(image_dir)
|
|
|
+ for idx, itemImg in enumerate(images):
|
|
|
+ if itemImg.image_path == "" or itemImg.image_path == None:
|
|
|
+ raise UnicornException(f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试")
|
|
|
+ new_file_name = (
|
|
|
+ str(idx)+"_"+str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
|
|
|
+ )
|
|
|
+ if not os.path.exists(
|
|
|
+ image_dir + "/" + os.path.basename(new_file_name)
|
|
|
+ ):
|
|
|
+ shutil.copy(itemImg.image_path, image_dir + new_file_name)
|
|
|
+ dealImage = DealImage(image_dir)
|
|
|
+ resFlag, path = dealImage.dealMoveImage(
|
|
|
+ image_dir=image_dir,
|
|
|
+ callback_func=None,
|
|
|
+ goods_art_no=goods_art_no,
|
|
|
+ )
|
|
|
+ if not resFlag:
|
|
|
+ raise UnicornException(f"抠图操作异常,请检查目录是否存在,或者权限不足")
|
|
|
+ session.close()
|
|
|
+ # try:
|
|
|
+ cutOutMode = (
|
|
|
+ "1"
|
|
|
+ if settings.getSysConfigs("other_configs", "cutout_mode", "普通抠图")
|
|
|
+ == "普通抠图"
|
|
|
+ else "2"
|
|
|
+ )
|
|
|
+ config_data = {
|
|
|
+ "image_dir": limit_path,
|
|
|
+ "image_order": (
|
|
|
+ "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5,组合6,组合7,组合8,组合9,组合10,组合11,组合12,组合13,组合14,组合15,组合16,组合17,组合18,组合19,组合20,组合21,组合22,组合23,组合24,组合25,组合26"
|
|
|
+ ),
|
|
|
+ "goods_art_no": "",
|
|
|
+ "goods_art_nos": goods_art_no_arrays,
|
|
|
+ "is_check_number": False,
|
|
|
+ "resize_image_view": "后跟",
|
|
|
+ "cutout_mode": cutOutMode,
|
|
|
+ "logo_path": "",
|
|
|
+ "special_goods_art_no_folder_line": "",
|
|
|
+ "is_use_excel": False, # 是否使用excel
|
|
|
+ "excel_path": "", # excel路径
|
|
|
+ "is_check_color_is_all": False,
|
|
|
+ "cutout_is_pass": True,
|
|
|
+ "assigned_page_dict": {},
|
|
|
+ "detail_is_pass": True,
|
|
|
+ "upload_is_pass": False,
|
|
|
+ "upload_is_enable": settings.IS_UPLOAD_HLM, # 是否上传到惠利玛商品库,通过config.ini得is_upload开启
|
|
|
+ "is_filter": False,
|
|
|
+ "temp_class": {},
|
|
|
+ "temp_name": "",
|
|
|
+ "temp_name_list": [],
|
|
|
+ "target_error_folder": f"{limit_path}/软件-生成详情错误",
|
|
|
+ "success_handler": [],
|
|
|
+ }
|
|
|
+ try:
|
|
|
+ loop = asyncio.get_event_loop()
|
|
|
+ return_data = await loop.run_in_executor(
|
|
|
+ executor, partial(run_main.check_before_cutout, config_data)
|
|
|
+ )
|
|
|
+ cutout_res = await loop.run_in_executor(
|
|
|
+ executor,
|
|
|
+ partial(run_main.check_for_cutout_image_first_call_back, return_data),
|
|
|
+ )
|
|
|
+ handler_result = []
|
|
|
+ have_handler_keys = move_folder_array.keys()
|
|
|
+ if cutout_res:
|
|
|
+ handler_result_folder = f"{config_data['image_dir']}"
|
|
|
+ for goods_art_item in goods_art_no_arrays:
|
|
|
+ handler_result.append({
|
|
|
+ "goods_art_no": goods_art_item,
|
|
|
+ "success": True,
|
|
|
+ "info": "处理成功",
|
|
|
+ })
|
|
|
+ else:
|
|
|
+ return {"code": 1, "message": "抠图失败", "data": None}
|
|
|
+ if len(have_handler_keys) == len(goods_art_no_arrays) or (len(have_handler_keys) == 0 and cutout_res):
|
|
|
+ handler_result_folder = handler_result_folder.replace("\\", "/")
|
|
|
+ success_items = [item for item in handler_result if item.get('success') == True]
|
|
|
+ cutout_folder = handler_result_folder+"/"+success_items[0].get("goods_art_no")+"/800x800" if len(success_items) > 0 else ""
|
|
|
+ progress = {
|
|
|
+ "status": "处理完成",
|
|
|
+ "current": len(goods_art_no_arrays),
|
|
|
+ "total": len(goods_art_no_arrays),
|
|
|
+ "error": 0,
|
|
|
+ "folder":cutout_folder,
|
|
|
+ }
|
|
|
+ return {"code": 0, "message": "抠图完成", "data": {"output_folder": handler_result_folder, "list": handler_result,"progress":progress}}
|
|
|
+ except UnicornException as e:
|
|
|
+ raise UnicornException(e.msg)
|
|
|
+ except Exception as e:
|
|
|
+ print("error",e)
|
|
|
+ raise UnicornException(f"抠图异常,请稍后重试:{e}")
|
|
|
+
|
|
|
+
|
|
|
+@app.post("/syncPhotoRecord", description="同步本地拍照记录-和output目录")
|
|
|
+async def syncPhotoRecord(params:SyncPhotoRecord):
|
|
|
+ # 查询所有不重复的货号及对应的最大时间,进行分页
|
|
|
+ settings.USER_TOKEN = params.token
|
|
|
+ settings.USER_ENV = params.env
|
|
|
+ syncStatus = settings.checkRecordSyncStatus()
|
|
|
+ if syncStatus == True:
|
|
|
+ # 同步过就无需再同步
|
|
|
+ return {"code": 0, "message": "同步完成", "data": None}
|
|
|
+ session = SqlQuery()
|
|
|
+ base_statement = (
|
|
|
+ select(PhotoRecord)
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
+ )
|
|
|
+ paginated_results = session.exec(base_statement).all()
|
|
|
+
|
|
|
+ def model_to_dict(model):
|
|
|
+ """将SQLAlchemy模型对象转换为字典,排除_sa_instance_state"""
|
|
|
+ result = {}
|
|
|
+ for column in model.__table__.columns:
|
|
|
+ result[column.name] = getattr(model, column.name)
|
|
|
+ return result
|
|
|
+
|
|
|
+ json_results = []
|
|
|
+ for result in paginated_results:
|
|
|
+ # 使用自定义函数将SQLAlchemy对象转换为字典
|
|
|
+ json_results.append(model_to_dict(result))
|
|
|
+ # 最终转换为JSON字符串
|
|
|
+ settings.syncPhotoRecord(json_results,action_type=0)
|
|
|
+ session.close()
|
|
|
+ return {"code": 0, "message": "同步完成", "data": None}
|
|
|
+def copy_directory_walk(src, dst):
|
|
|
+ """
|
|
|
+ 使用 os.walk() 遍历并复制目录
|
|
|
+ """
|
|
|
+ for root, dirs, files in os.walk(src):
|
|
|
+ # 计算相对路径
|
|
|
+ rel_path = os.path.relpath(root, src)
|
|
|
+ dst_dir = os.path.join(dst, rel_path) if rel_path != '.' else dst
|
|
|
+ # 创建目标目录
|
|
|
+ if not os.path.exists(dst_dir):
|
|
|
+ os.makedirs(dst_dir)
|
|
|
+ # 复制文件
|
|
|
+ for file in files:
|
|
|
+ src_file = os.path.join(root, file)
|
|
|
+ dst_file = os.path.join(dst_dir, file)
|
|
|
+ shutil.copy2(src_file, dst_file)
|
|
|
+def rename_file_safe(src, dst, overwrite=True):
|
|
|
+ """
|
|
|
+ 安全地重命名文件
|
|
|
+
|
|
|
+ Args:
|
|
|
+ src: 源文件路径
|
|
|
+ dst: 新文件路径
|
|
|
+ overwrite: 是否覆盖已存在的文件
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 检查源文件是否存在
|
|
|
+ if not os.path.exists(src):
|
|
|
+ return False, f"源文件 {src} 不存在"
|
|
|
+
|
|
|
+ # 检查目标文件是否存在
|
|
|
+ if os.path.exists(dst) and not overwrite:
|
|
|
+ return False, f"目标文件 {dst} 已存在,设置 overwrite=True 以覆盖"
|
|
|
+
|
|
|
+ # 执行重命名
|
|
|
+ os.rename(src, dst)
|
|
|
+ return True, f"文件已成功从 {src} 重命名为 {dst}"
|
|
|
+ except OSError as e:
|
|
|
+ return False, f"重命名失败: {str(e)}"
|
|
|
+@app.post("/rename_shadow_folder", description="同步本地拍照记录-和output目录")
|
|
|
+async def rename_shadow_folder(params:RenameShadow):
|
|
|
+ # 货号数组
|
|
|
+ goods_art_nos = params.goods_art_nos
|
|
|
+ # for goods_art_no in goods_art_nos:
|
|
|
+ # 查询这些货号的所有记录
|
|
|
+ goods_art_dict = {}
|
|
|
+ for goods in goods_art_nos:
|
|
|
+ query = (
|
|
|
+ select(PhotoRecord, DeviceConfig.action_name)
|
|
|
+ .outerjoin(DeviceConfig, PhotoRecord.action_id == DeviceConfig.id)
|
|
|
+ .where(PhotoRecord.goods_art_no.in_(goods_art_nos))
|
|
|
+ .where(PhotoRecord.delete_time == None)
|
|
|
+ .order_by(PhotoRecord.goods_art_no, asc("id")) # 按货号分组并按ID倒序
|
|
|
+ )
|
|
|
+ all_items = session.exec(query).mappings().all()
|
|
|
+ if len(all_items) == 0: # 如果没有记录则返回
|
|
|
+ # raise UnicornException("暂无可用货号")
|
|
|
+ continue
|
|
|
+ goods_art_rename_list = []
|
|
|
+ for item in all_items:
|
|
|
+ if item["action_name"] == None:
|
|
|
+ continue
|
|
|
+ data = {"goods_art_no": item.PhotoRecord.goods_art_no, "action_name": item["action_name"],"image_index":item.PhotoRecord.image_index}
|
|
|
+ goods_art_rename_list.append(data)
|
|
|
+ goods_art_dict[goods] = goods_art_rename_list
|
|
|
+ outputDir = settings.OUTPUT_DIR
|
|
|
+ if not os.path.exists(outputDir):
|
|
|
+ raise UnicornException(f"生成目录[{outputDir}]暂无文件,请拍摄或抠图后处理")
|
|
|
+ outputList = os.listdir(outputDir)
|
|
|
+ success_result = []
|
|
|
+ for firstDir in outputList:
|
|
|
+ secondPath = f"{outputDir}\\{firstDir}"
|
|
|
+ for goodsArt in goods_art_dict:
|
|
|
+ goods_art_no_obj = goods_art_dict[goodsArt]
|
|
|
+ goodsArtPath = f"{secondPath}\\{goodsArt}"
|
|
|
+ if not os.path.exists(goodsArtPath):
|
|
|
+ continue
|
|
|
+ renameSrcPath = f"{goodsArtPath}\\阴影图处理"
|
|
|
+ renameDstPath = f"{goodsArtPath}\\阴影图处理-重命名"
|
|
|
+ if not os.path.exists(renameSrcPath):
|
|
|
+ print("阴影图目录不存在...","不处理")
|
|
|
+ continue
|
|
|
+ if len(os.listdir(renameSrcPath)) == 0:
|
|
|
+ print("阴影图处理目录无内容...","不处理")
|
|
|
+ continue
|
|
|
+ if not os.path.exists(renameDstPath):
|
|
|
+ try:
|
|
|
+ copy_directory_walk(renameSrcPath,renameDstPath)
|
|
|
+ except Exception as e:
|
|
|
+ print("重命名失败",e)
|
|
|
+ continue
|
|
|
+ dstPath = os.listdir(renameDstPath)
|
|
|
+ for dts_files in dstPath:
|
|
|
+ for goods_obj in goods_art_no_obj:
|
|
|
+ goods_art_no_name = goods_obj["goods_art_no"]
|
|
|
+ image_index = goods_obj["image_index"]
|
|
|
+ action_name = goods_obj["action_name"]
|
|
|
+ image_index+=1
|
|
|
+ basic_name = f"{goods_art_no_name}({image_index})"
|
|
|
+ if basic_name in dts_files:
|
|
|
+ if "抠图" in dts_files:
|
|
|
+ is_ok,msg = rename_file_safe(f"{renameDstPath}\\{dts_files}",f"{renameDstPath}\\{basic_name}_{action_name}_抠图.png")
|
|
|
+ print(is_ok,msg)
|
|
|
+ if "阴影" in dts_files:
|
|
|
+ is_ok,msg = rename_file_safe(f"{renameDstPath}\\{dts_files}",f"{renameDstPath}\\{basic_name}_{action_name}_阴影.png")
|
|
|
+ print(is_ok,msg)
|
|
|
+ print("goods_obj",goods_obj)
|
|
|
+ success_result.append({"goods_art_no":goodsArt,"path":renameDstPath})
|
|
|
+ return {"code": 0, "message": "重命名完成", "data": {"result": success_result}}
|