api.py 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  1. from re import search
  2. from natsort.natsort import order_by_index
  3. from sqlalchemy import func
  4. from models import *
  5. import requests
  6. import json
  7. from logger import logger
  8. from serial.tools import list_ports
  9. from model import PhotoRecord
  10. import settings, datetime
  11. import pandas as pd
  12. from utils.hlm_http_request import forward_request
  13. from utils.utils_func import check_path
  14. from sockets.socket_client import socket_manager
  15. from mcu.DeviceControl import DeviceControl
  16. import time, shutil, os
  17. from sqlalchemy import and_, asc, desc
  18. from functools import partial
  19. from service.deal_image import DealImage
  20. from databases import DeviceConfig, SysConfigs, SqlQuery, CRUD, select, DeviceConfigTabs
  21. from service.run_main import RunMain
  22. import importlib
  23. from service.auto_deal_pics.upload_pic import UploadPic
  24. from service.OnePicTest import OnePicTest
  25. from service.base import check_move_goods_art_no_folder
  26. import win32api, win32gui, win32con
  27. from win32gui import EnumWindows, GetWindowText
  28. from service.online_request.module_online_data import OnlineDataRequest
  29. from concurrent.futures import ThreadPoolExecutor
  30. from functools import partial
  31. from service.online_request.module_online_data import AIGCDataRequest
  32. import asyncio
  33. from fastapi import BackgroundTasks
  34. import functools
  35. import traceback
  36. def log_exception_with_context(context_message=""):
  37. """装饰器:为函数添加异常日志上下文"""
  38. def decorator(func):
  39. @functools.wraps(func)
  40. def wrapper(*args, **kwargs):
  41. try:
  42. return func(*args, **kwargs)
  43. except Exception as e:
  44. logger.error(f"=== 异常发生在函数: {func.__name__} ===")
  45. if context_message:
  46. logger.error(f"上下文信息: {context_message}")
  47. logger.error(f"函数参数: args={args}, kwargs={kwargs}")
  48. logger.error(f"异常类型: {type(e).__name__}")
  49. logger.error(f"异常信息: {str(e)}")
  50. logger.error("完整堆栈跟踪:")
  51. logger.error(traceback.format_exc())
  52. raise # 重新抛出异常
  53. return wrapper
  54. return decorator
  55. def parserGoodsDict2Aigc(return_data_check_before_detail):
  56. """获取商品组装数据"""
  57. goods_no_dict = return_data_check_before_detail.get("data", {}).get(
  58. "goods_no_dict", {}
  59. )
  60. return goods_no_dict
  61. async def sendAsyncMessage(msg="", goods_arts=[], status="", msg_type="", data=None):
  62. """异步发送消息"""
  63. data = {
  64. "code": 0,
  65. "msg": msg,
  66. "status": 2,
  67. "data": (
  68. data
  69. if data is not None
  70. else {
  71. "status": status,
  72. "goods_art_nos": goods_arts,
  73. }
  74. ),
  75. "msg_type": msg_type,
  76. }
  77. await message_queue.put(data)
  78. @app.get("/")
  79. async def index():
  80. # await socket_manager.send_message(msg="测试")
  81. return {"message": "Hello World"}
  82. @app.get("/scan_serials", description="扫描可用的设备端口")
  83. async def scanSerials():
  84. """扫描串口"""
  85. ports = list_ports.comports()
  86. print("Scanning", ports)
  87. return {"message": "Hello World"}
  88. @app.api_route(
  89. "/forward_request", methods=["GET", "POST"], description="代理转发hlm项目得请求"
  90. )
  91. async def forwardRequest(request: HlmForwardRequest):
  92. """
  93. 转发HTTP请求到目标URL
  94. :param request: FastAPI Request对象
  95. :return: 目标接口的响应
  96. """
  97. try:
  98. if request.method == "GET":
  99. params = request.query_params
  100. elif request.method == "POST":
  101. params = json.dump(request.query_params)
  102. else:
  103. raise UnicornException("仅支持GET和POST方法")
  104. target_url = request.target_url
  105. method = request.method.upper()
  106. headers = request.headers
  107. if not target_url:
  108. raise UnicornException("目标url地址不能为空")
  109. # 调用 hlm_http_request 中的 forward_request 函数
  110. response = forward_request(
  111. target_url, params=params, method=method, headers=headers
  112. )
  113. return response
  114. except requests.RequestException as e:
  115. raise UnicornException(e)
  116. except Exception as e:
  117. raise UnicornException(e)
  118. async def fromExcelHandler(params: HandlerDetail):
  119. obj = None
  120. excel_path = params.excel_path
  121. token = "Bearer " + params.token
  122. uuid = params.uuid
  123. aigc_clazz = AIGCDataRequest(token)
  124. run_main = RunMain(obj, token, uuid)
  125. onlineData = OnlineDataRequest(token)
  126. excel_df = pd.read_excel(excel_path, sheet_name=0, header=0)
  127. online_stores = params.online_stores # 上传第三方的店铺名称数组
  128. is_product_scene = params.is_product_scene # 上传第三方的店铺名称数组
  129. is_upper_footer = params.is_upper_footer # 上传第三方的店铺名称数组
  130. upper_footer_params = params.upper_footer_params # 上传第三方的店铺名称数组
  131. product_scene_prompt = params.product_scene_prompt # 上传第三方的店铺名称数组
  132. handler_result = []
  133. handler_result_folder = ""
  134. if "文件夹名称" not in excel_df.columns:
  135. raise UnicornException("缺失 [文件夹名称] 列")
  136. if "商品货号" not in excel_df.columns:
  137. raise UnicornException("缺失 [商品货号] 列")
  138. if "款号" not in excel_df.columns:
  139. raise UnicornException("缺失 [款号] 列")
  140. goods_art_dirs = excel_df.groupby(excel_df["款号"])
  141. # 抠图时用到的货号列表,与生成详情图有所区别
  142. goods_art_no_arrays = []
  143. # # 详情图生成需要对同款商品进行分组,保证详情图可以生成多个色
  144. goods_art_no_group_arrays = []
  145. for _, goods_row in excel_df.iterrows():
  146. goods_art_no = str(goods_row["商品货号"])
  147. goods_art_no_arrays.append(goods_art_no)
  148. goods_no = str(goods_row["款号"])
  149. a001_df = goods_art_dirs.get_group(goods_no)
  150. goods_art_groups = a001_df["商品货号"].tolist()
  151. if goods_art_groups in goods_art_no_group_arrays:
  152. continue
  153. goods_art_no_group_arrays.append(goods_art_groups)
  154. limit_path = "output/{}".format(
  155. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  156. )
  157. # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
  158. move_folder_array = check_move_goods_art_no_folder(
  159. "output", goods_art_no_arrays, limit_path
  160. )
  161. try:
  162. for index, row in excel_df.iterrows():
  163. goods_art_no_image_dir = str(row["文件夹名称"])
  164. goods_art_no = str(row["商品货号"])
  165. print("货号数据", goods_art_no)
  166. if not goods_art_no:
  167. raise UnicornException("货号不能为空")
  168. session = SqlQuery()
  169. pr = CRUD(PhotoRecord)
  170. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
  171. if not images:
  172. raise UnicornException(
  173. f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确"
  174. )
  175. # 货号目录不存在再去进行移动和创建操作
  176. if move_folder_array.get(goods_art_no) == None:
  177. image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
  178. check_path(image_dir)
  179. for idx, itemImg in enumerate(images):
  180. if itemImg.image_path == "" or itemImg.image_path == None:
  181. raise UnicornException(
  182. f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试"
  183. )
  184. new_file_name = str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
  185. if not os.path.exists(
  186. image_dir + "/" + os.path.basename(new_file_name)
  187. ):
  188. shutil.copy(itemImg.image_path, image_dir + new_file_name)
  189. dealImage = DealImage(image_dir)
  190. resFlag, path = dealImage.dealMoveImage(
  191. image_dir=image_dir,
  192. callback_func=None,
  193. goods_art_no=goods_art_no_image_dir,
  194. )
  195. if not resFlag:
  196. raise UnicornException(path)
  197. shutil.rmtree(image_dir)
  198. # path = os.path.dirname(path)
  199. except UnicornException as e:
  200. handler_result_folder = ""
  201. handler_result.append(
  202. {"goods_art_no": "", "success": False, "info": str(e.msg)}
  203. )
  204. print(f"UnicornException 生成错误信息:{e}")
  205. await sendAsyncMessage(
  206. msg="处理结束",
  207. data={"output_folder": handler_result_folder, "list": handler_result},
  208. status="处理结束",
  209. msg_type="detail_result_progress",
  210. )
  211. return True
  212. except Exception as e:
  213. print(f"详情图生成错误信息:{e}")
  214. handler_result_folder = ""
  215. handler_result.append({"goods_art_no": "", "success": False, "info": str(e)})
  216. await sendAsyncMessage(
  217. msg="处理结束",
  218. data={"output_folder": handler_result_folder, "list": handler_result},
  219. status="处理结束",
  220. msg_type="detail_result_progress",
  221. )
  222. return True
  223. temp_class = {}
  224. # 可用模板列表-需要导包
  225. temp_name_list = []
  226. for tempItem in params.temp_list:
  227. temp_class[tempItem.template_id] = tempItem.template_local_classes
  228. temp_name_list.append(tempItem.template_id)
  229. cutOutMode = (
  230. "0"
  231. if settings.getSysConfigs("other_configs", "cutout_mode", "普通抠图")
  232. == "普通抠图"
  233. else "1"
  234. )
  235. config_data = {
  236. "image_dir": limit_path, # 这个目录作为本次生成的图片目录非常重要 例:./output/当前日期
  237. "image_order": (
  238. "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5"
  239. if params.template_image_order == None or params.template_image_order == ""
  240. else params.template_image_order
  241. ),
  242. "goods_art_no": goods_art_no,
  243. "goods_art_nos": goods_art_no_arrays,
  244. "is_check_number": False,
  245. "resize_image_view": "后跟",
  246. "cutout_mode": cutOutMode,
  247. "logo_path": params.logo_path,
  248. "special_goods_art_no_folder_line": "",
  249. "is_use_excel": (False if params.excel_path == "" else True), # 是否使用excel
  250. "excel_path": params.excel_path, # excel路径
  251. "is_check_color_is_all": False,
  252. "cutout_is_pass": True,
  253. "assigned_page_dict": {},
  254. "detail_is_pass": True,
  255. "upload_is_pass": False,
  256. "upload_is_enable": False,
  257. "is_filter": False,
  258. "temp_class": temp_class,
  259. "temp_name": params.temp_name,
  260. "temp_name_list": temp_name_list,
  261. "target_error_folder": f"{limit_path}/软件-生成详情错误",
  262. "success_handler": [],
  263. }
  264. # 动态导入类
  265. temp_class_dict = {}
  266. for key, class_path in config_data["temp_class"].items():
  267. module_path, class_name = class_path.rsplit(".", 1)
  268. module = importlib.import_module(module_path)
  269. cls = getattr(module, class_name)
  270. temp_class_dict[key] = cls
  271. config_data["temp_class"] = temp_class_dict
  272. # executor = ThreadPoolExecutor(max_workers=4)
  273. # 此处对抠图进行批量处理,保证所有的图片在生成详情图之前已经完成抠图,以保证详情图生成的效率
  274. return_data = run_main.check_before_cutout(config_data)
  275. cutout_res = run_main.check_for_cutout_image_first_call_back(return_data)
  276. check_for_detail_first_res = None
  277. if cutout_res == True:
  278. sys_path = format(os.getcwd()).replace("\\", "/")
  279. handler_result_folder = f"{sys_path}/{limit_path}"
  280. for goods_art_item in goods_art_no_arrays:
  281. handler_result.append(
  282. {
  283. "goods_art_no": goods_art_item,
  284. "success": True,
  285. "info": "处理成功",
  286. }
  287. )
  288. try:
  289. if is_product_scene == 1:
  290. if product_scene_prompt == "" or product_scene_prompt == None:
  291. raise UnicornException("请填写场景描述")
  292. if is_upper_footer == 1:
  293. if upper_footer_params == {} or upper_footer_params == None:
  294. raise UnicornException("请选择模特")
  295. man_id = upper_footer_params.get("man_id")
  296. if not man_id:
  297. raise UnicornException("请选择男模特")
  298. women_id = upper_footer_params.get("women_id")
  299. if not women_id:
  300. raise UnicornException("请选择女模特")
  301. return_data_check_before_detail = run_main.check_before_detail(config_data)
  302. print("报错前返回的结果数据", return_data_check_before_detail)
  303. if is_product_scene == 1:
  304. goods_dict = parserGoodsDict2Aigc(return_data_check_before_detail)
  305. new_goods_dict = {}
  306. await sendAsyncMessage(
  307. msg="开始处理场景图",
  308. goods_arts=[goods_art_no for goods_art_no in goods_dict.keys()],
  309. status="开始处理",
  310. msg_type="scene_progress",
  311. )
  312. for goods_art_no in goods_dict.keys():
  313. print("处理场景图", goods_art_no)
  314. goods_art_dict_info = goods_dict[goods_art_no]
  315. first_goods_art_no_info = goods_art_dict_info.get("货号资料", [])[0]
  316. first_pics = first_goods_art_no_info.get("pics")
  317. ceshi_image_path = first_pics.get("侧视-抠图")
  318. save_root_path = ceshi_image_path.split("阴影图处理")[0]
  319. save_image_path = f"{save_root_path}场景图.jpg"
  320. if os.path.isfile(save_image_path):
  321. goods_art_dict_info["场景图"] = save_image_path
  322. new_goods_dict[goods_art_no] = goods_art_dict_info
  323. continue
  324. aigc_clazz.center_paste_image(ceshi_image_path, save_image_path)
  325. try:
  326. image_path = aigc_clazz.generateProductScene(
  327. save_image_path, product_scene_prompt, save_image_path
  328. )
  329. # image_path = aigc_clazz.generateProductSceneQW(
  330. # save_image_path, product_scene_prompt, save_image_path
  331. # )
  332. goods_art_dict_info["场景图"] = image_path
  333. new_goods_dict[goods_art_no] = goods_art_dict_info
  334. handler_result.append(
  335. {
  336. "goods_art_no": goods_art_no,
  337. "success": True,
  338. "info": "场景图处理成功",
  339. }
  340. )
  341. await sendAsyncMessage(
  342. msg="场景图处理完成",
  343. goods_arts=[goods_art_no],
  344. status="场景图处理完成",
  345. msg_type="scene_progress",
  346. )
  347. except Exception as e:
  348. os.remove(save_image_path)
  349. handler_result.append(
  350. {
  351. "goods_art_no": goods_art_no,
  352. "success": False,
  353. "info": f"场景图处理失败:{e}",
  354. }
  355. )
  356. await sendAsyncMessage(
  357. msg="场景图处理失败",
  358. goods_arts=[goods_art_no],
  359. status="场景图处理失败",
  360. msg_type="scene_progress",
  361. )
  362. if new_goods_dict is not None or new_goods_dict != {}:
  363. return_data_check_before_detail["data"][
  364. "goods_no_dict"
  365. ] = new_goods_dict
  366. if is_upper_footer == 1:
  367. goods_dict = parserGoodsDict2Aigc(return_data_check_before_detail)
  368. new_goods_dict = {}
  369. await sendAsyncMessage(
  370. msg="开始处理模特图",
  371. goods_arts=list(goods_dict.keys()),
  372. status="开始处理模特图",
  373. msg_type="upper_footer_progress",
  374. )
  375. for goods_art_no in goods_dict.keys():
  376. goods_art_dict_info = goods_dict[goods_art_no]
  377. first_goods_art_no_info = goods_art_dict_info.get("货号资料", [])[0]
  378. first_pics = first_goods_art_no_info.get("pics")
  379. gender = goods_art_dict_info.get("性别")
  380. model_id = man_id if "男" in gender else women_id
  381. ceshi_image_path = first_pics.get("侧视-抠图")
  382. save_root_path = ceshi_image_path.split("阴影图处理")[0]
  383. save_image_path = f"{save_root_path}模特图.jpg"
  384. if os.path.isfile(save_image_path):
  385. goods_art_dict_info["模特图"] = save_image_path
  386. new_goods_dict[goods_art_no] = goods_art_dict_info
  387. continue
  388. shutil.copy(ceshi_image_path, save_image_path)
  389. try:
  390. image_path = aigc_clazz.generateUpperShoes(
  391. save_image_path, model_id, save_image_path
  392. )
  393. # image_path = aigc_clazz.generateModelShoesQW(
  394. # save_image_path, model_id, save_image_path
  395. # )
  396. goods_art_dict_info["模特图"] = image_path
  397. new_goods_dict[goods_art_no] = goods_art_dict_info
  398. handler_result.append(
  399. {
  400. "goods_art_no": goods_art_no,
  401. "success": True,
  402. "info": "模特图处理成功",
  403. }
  404. )
  405. await sendAsyncMessage(
  406. msg="模特图处理成功",
  407. goods_arts=[goods_art_no],
  408. status="模特图处理成功",
  409. msg_type="upper_footer_progress",
  410. )
  411. except Exception as e:
  412. os.remove(save_image_path)
  413. handler_result.append(
  414. {
  415. "goods_art_no": goods_art_no,
  416. "success": False,
  417. "info": f"模特图处理失败:{e}",
  418. }
  419. )
  420. await sendAsyncMessage(
  421. msg="模特图处理失败",
  422. goods_arts=[goods_art_no],
  423. status="模特图处理失败",
  424. msg_type="upper_footer_progress",
  425. )
  426. if new_goods_dict is not None or new_goods_dict != {}:
  427. return_data_check_before_detail["data"][
  428. "goods_no_dict"
  429. ] = new_goods_dict
  430. await sendAsyncMessage(
  431. msg="开始处理详情页",
  432. goods_arts=[],
  433. status="开始处理详情页",
  434. msg_type="detail_progress",
  435. )
  436. check_for_detail_first_res = run_main.check_for_detail_first_call_back(
  437. return_data_check_before_detail
  438. )
  439. if isinstance(check_for_detail_first_res, partial):
  440. result = check_for_detail_first_res()
  441. try:
  442. config_data = result["config_data"]
  443. except:
  444. config_data = result
  445. if config_data["sign_text"] == "已结束详情处理":
  446. await sendAsyncMessage(
  447. msg="详情页处理结束",
  448. goods_arts=[],
  449. status="详情页处理结束",
  450. msg_type="detail_progress",
  451. )
  452. print("config_data", config_data)
  453. # if config_data["upload_is_enable"]:
  454. # to_deal_dir = "{}/软件-详情图生成".format(config_data["image_dir"])
  455. # check_path(to_deal_dir)
  456. # print("to_deal_dir", to_deal_dir)
  457. # if os.path.exists(to_deal_dir):
  458. # upload_pic = UploadPic(
  459. # windows=None,
  460. # to_deal_dir=to_deal_dir,
  461. # config_data=config_data,
  462. # token=token,
  463. # )
  464. # upload_pic.run()
  465. out_put_dir = config_data.get("out_put_dir")
  466. if out_put_dir == None:
  467. handler_result_folder = ""
  468. if len(config_data["success_handler"]) > 0:
  469. for good_art in config_data["success_handler"]:
  470. handler_result.append(good_art)
  471. else:
  472. for good_art in goods_art_no_arrays:
  473. handler_result.append(
  474. {
  475. "goods_art_no": good_art,
  476. "success": False,
  477. "info": "处理失败",
  478. }
  479. )
  480. else:
  481. out_put_dir_path = "{}/{}".format(os.getcwd(), out_put_dir).replace(
  482. "\\", "/"
  483. )
  484. handler_result_folder = os.path.dirname(out_put_dir_path)
  485. if len(config_data["success_handler"]) == 0:
  486. for good_art in goods_art_no_arrays:
  487. handler_result.append(
  488. {
  489. "goods_art_no": good_art,
  490. "success": False,
  491. "info": "处理失败",
  492. }
  493. )
  494. else:
  495. if len(online_stores) > 0:
  496. result_goods_no_dict = return_data_check_before_detail["data"][
  497. "goods_no_dict"
  498. ]
  499. for goods_idx, goods_no_dict in enumerate(
  500. result_goods_no_dict.keys()
  501. ):
  502. all_detail_path_list = config_data["all_detail_path_list"]
  503. for detail_path in all_detail_path_list:
  504. if goods_no_dict in detail_path:
  505. detail_path_replace = detail_path.replace("\\", "/")
  506. result_goods_no_dict[goods_no_dict][
  507. "detail_path"
  508. ] = f"{detail_path_replace}/详情页.jpg"
  509. await sendAsyncMessage(
  510. msg="开始上传商品数据",
  511. goods_arts=[],
  512. status="开始上传商品数据",
  513. msg_type="upload_goods_progress",
  514. )
  515. try:
  516. onlineData.uploadGoods2ThirdParty(
  517. result_goods_no_dict, online_stores=online_stores
  518. )
  519. except Exception as e:
  520. print(f"上传任务出现错误:{e}")
  521. await sendAsyncMessage(
  522. msg="商品上传第三方成功",
  523. goods_arts=[],
  524. status="商品上传第三方成功",
  525. msg_type="upload_goods_progress",
  526. )
  527. handler_result = config_data["success_handler"]
  528. else:
  529. for good_art in goods_art_no_arrays:
  530. handler_result.append(
  531. {"goods_art_no": good_art, "success": False, "info": "处理失败"}
  532. )
  533. except UnicornException as e:
  534. handler_result_folder = ""
  535. handler_result.append(
  536. {"goods_art_no": "", "success": False, "info": str(e.msg)}
  537. )
  538. print(f"UnicornException 生成错误信息:{e}")
  539. except Exception as e:
  540. for good_art in goods_art_no_arrays:
  541. handler_result.append(
  542. {"goods_art_no": good_art, "success": False, "info": str(e)}
  543. )
  544. handler_result_folder = "/".join(handler_result_folder.split("/")[:-1])
  545. await sendAsyncMessage(
  546. msg="处理结束",
  547. data={"output_folder": handler_result_folder, "list": handler_result},
  548. status="处理结束",
  549. msg_type="detail_result_progress",
  550. )
  551. return True
  552. def group_by_style_number(data):
  553. result = {}
  554. for goods_id, info in data.items():
  555. style_number = info["款号"]
  556. if style_number not in result:
  557. result[style_number] = []
  558. result[style_number].append(goods_id)
  559. return result
  560. @app.post("/handle_detail")
  561. async def handle_detail_background(
  562. request: Request, params: HandlerDetail, background_tasks: BackgroundTasks
  563. ):
  564. goods_art_no_arrays = params.goods_art_no
  565. is_check = params.is_check
  566. is_only_cutout = params.is_only_cutout # 是否仅抠图
  567. if is_only_cutout == 1:
  568. # 如果是仅抠图模式,避免进入到excel模式
  569. params.excel_path = ""
  570. if params.excel_path != "" and params.excel_path != None:
  571. return await fromExcelHandler(params)
  572. path = ""
  573. limit_path = "output/{}".format(
  574. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  575. )
  576. check_path(limit_path)
  577. # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
  578. move_folder_array = check_move_goods_art_no_folder(
  579. "output", goods_art_no_arrays, limit_path
  580. )
  581. try:
  582. for goods_art_no in goods_art_no_arrays:
  583. if not goods_art_no:
  584. raise UnicornException("货号不能为空")
  585. session = SqlQuery()
  586. pr = CRUD(PhotoRecord)
  587. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
  588. if not images:
  589. raise UnicornException(
  590. f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确"
  591. )
  592. if is_only_cutout != 1:
  593. detail_counts = len(params.template_image_order.split(","))
  594. image_counts = len(images)
  595. if image_counts < detail_counts:
  596. raise UnicornException(
  597. f"货号:[{goods_art_no}],实际照片数量:{image_counts}张,小于详情图要求数量:{detail_counts}张"
  598. )
  599. if move_folder_array.get(goods_art_no) == None:
  600. image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
  601. check_path(image_dir)
  602. for idx, itemImg in enumerate(images):
  603. if itemImg.image_path == "" or itemImg.image_path == None:
  604. raise UnicornException(
  605. f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试"
  606. )
  607. new_file_name = str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
  608. if not os.path.exists(
  609. image_dir + "/" + os.path.basename(new_file_name)
  610. ):
  611. shutil.copy(itemImg.image_path, image_dir + new_file_name)
  612. dealImage = DealImage(image_dir)
  613. resFlag, path = dealImage.dealMoveImage(
  614. image_dir=image_dir, callback_func=None, goods_art_no=goods_art_no
  615. )
  616. if not resFlag:
  617. raise UnicornException(path)
  618. except Exception as e:
  619. raise UnicornException(str(e))
  620. if is_check == 1:
  621. return {
  622. "code": 0,
  623. "msg": "检测通过",
  624. "data": None,
  625. }
  626. asyncio.create_task(process_handle_detail(request, params))
  627. return {"code": 0, "msg": "任务已提交后台处理", "data": {"status": "processing"}}
  628. async def process_handle_detail(request: Request, params: HandlerDetail):
  629. obj = None
  630. token = "Bearer " + params.token
  631. uuid = params.uuid
  632. aigc_clazz = AIGCDataRequest(token)
  633. run_main = RunMain(obj, token, uuid)
  634. onlineData = OnlineDataRequest(token)
  635. goods_art_no_arrays = params.goods_art_no
  636. is_only_cutout = params.is_only_cutout # 是否仅抠图
  637. online_stores = params.online_stores # 上传第三方的店铺名称数组
  638. is_detail = params.is_detail # 上传第三方的店铺名称数组
  639. is_product_scene = params.is_product_scene # 上传第三方的店铺名称数组
  640. is_upper_footer = params.is_upper_footer # 上传第三方的店铺名称数组
  641. upper_footer_params = params.upper_footer_params # 上传第三方的店铺名称数组
  642. product_scene_prompt = params.product_scene_prompt # 上传第三方的店铺名称数组
  643. handler_result = []
  644. handler_result_folder = ""
  645. if is_only_cutout == 1:
  646. # 如果是仅抠图模式,避免进入到excel模式
  647. params.excel_path = ""
  648. if params.excel_path != "" and params.excel_path != None:
  649. return await fromExcelHandler(params)
  650. path = ""
  651. limit_path = "output/{}".format(
  652. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  653. )
  654. check_path(limit_path)
  655. # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
  656. move_folder_array = check_move_goods_art_no_folder(
  657. "output", goods_art_no_arrays, limit_path
  658. )
  659. try:
  660. for goods_art_no in goods_art_no_arrays:
  661. if not goods_art_no:
  662. raise UnicornException("货号不能为空")
  663. session = SqlQuery()
  664. pr = CRUD(PhotoRecord)
  665. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
  666. if not images:
  667. raise UnicornException(
  668. f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确"
  669. )
  670. if is_only_cutout != 1:
  671. detail_counts = len(params.template_image_order.split(","))
  672. image_counts = len(images)
  673. if image_counts < detail_counts:
  674. raise UnicornException(
  675. f"货号:[{goods_art_no}],实际照片数量:{image_counts}张,小于详情图要求数量:{detail_counts}张"
  676. )
  677. if move_folder_array.get(goods_art_no) == None:
  678. image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
  679. check_path(image_dir)
  680. for idx, itemImg in enumerate(images):
  681. if itemImg.image_path == "" or itemImg.image_path == None:
  682. raise UnicornException(
  683. f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试"
  684. )
  685. new_file_name = str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
  686. if not os.path.exists(
  687. image_dir + "/" + os.path.basename(new_file_name)
  688. ):
  689. shutil.copy(itemImg.image_path, image_dir + new_file_name)
  690. dealImage = DealImage(image_dir)
  691. resFlag, path = dealImage.dealMoveImage(
  692. image_dir=image_dir, callback_func=None, goods_art_no=goods_art_no
  693. )
  694. if not resFlag:
  695. raise UnicornException(path)
  696. except UnicornException as e:
  697. handler_result_folder = ""
  698. handler_result.append(
  699. {"goods_art_no": "", "success": False, "info": str(e.msg)}
  700. )
  701. print(f"UnicornException 生成错误信息:{e}")
  702. await sendAsyncMessage(
  703. msg="处理结束",
  704. data={"output_folder": handler_result_folder, "list": handler_result},
  705. status="处理结束",
  706. msg_type="detail_result_progress",
  707. )
  708. return True
  709. except Exception as e:
  710. print(f"详情图生成错误信息:{e}")
  711. handler_result_folder = ""
  712. handler_result.append({"goods_art_no": "", "success": False, "info": str(e)})
  713. await sendAsyncMessage(
  714. msg="处理结束",
  715. data={"output_folder": handler_result_folder, "list": handler_result},
  716. status="处理结束",
  717. msg_type="detail_result_progress",
  718. )
  719. return True
  720. # try:
  721. temp_class = {}
  722. temp_name_list = []
  723. for tempItem in params.temp_list:
  724. temp_class[tempItem.template_id] = tempItem.template_local_classes
  725. temp_name_list.append(tempItem.template_id)
  726. cutOutMode = (
  727. "1"
  728. if settings.getSysConfigs("other_configs", "cutout_mode", "普通抠图")
  729. == "普通抠图"
  730. else "2"
  731. )
  732. config_data = {
  733. "image_dir": limit_path,
  734. "image_order": (
  735. "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5"
  736. if params.template_image_order == None or params.template_image_order == ""
  737. else params.template_image_order
  738. ),
  739. "goods_art_no": "",
  740. "goods_art_nos": goods_art_no_arrays,
  741. "is_check_number": False,
  742. "resize_image_view": "后跟",
  743. "cutout_mode": cutOutMode,
  744. "logo_path": params.logo_path,
  745. "special_goods_art_no_folder_line": "",
  746. "is_use_excel": False, # 是否使用excel
  747. "excel_path": "", # excel路径
  748. "is_check_color_is_all": False,
  749. "cutout_is_pass": True,
  750. "assigned_page_dict": {},
  751. "detail_is_pass": True,
  752. "upload_is_pass": False,
  753. "upload_is_enable": settings.IS_UPLOAD_HLM, # 是否上传到惠利玛商品库,通过config.ini得is_upload开启
  754. "is_filter": False,
  755. "temp_class": temp_class,
  756. "temp_name": params.temp_name,
  757. "temp_name_list": temp_name_list,
  758. "target_error_folder": f"{limit_path}/软件-生成详情错误",
  759. "success_handler": [],
  760. }
  761. print("image_dir=====>>>>>", config_data["image_dir"])
  762. # 动态导入类
  763. temp_class_dict = {}
  764. for key, class_path in config_data["temp_class"].items():
  765. module_path, class_name = class_path.rsplit(".", 1)
  766. module = importlib.import_module(module_path)
  767. cls = getattr(module, class_name)
  768. temp_class_dict[key] = cls
  769. config_data["temp_class"] = temp_class_dict
  770. return_data = run_main.check_before_cutout(config_data)
  771. cutout_res = run_main.check_for_cutout_image_first_call_back(return_data)
  772. check_for_detail_first_res = None
  773. if cutout_res == True:
  774. sys_path = format(os.getcwd()).replace("\\", "/")
  775. handler_result_folder = f"{sys_path}/{limit_path}"
  776. for goods_art_item in goods_art_no_arrays:
  777. handler_result.append(
  778. {
  779. "goods_art_no": goods_art_item,
  780. "success": True,
  781. "info": "处理成功",
  782. }
  783. )
  784. if is_only_cutout == 1:
  785. # return {
  786. # "code": 0,
  787. # "msg": "",
  788. # "data": {"output_folder": handler_result_folder, "list": handler_result},
  789. # }
  790. await sendAsyncMessage(
  791. msg="处理结束",
  792. data={"output_folder": handler_result_folder, "list": handler_result},
  793. status="处理结束",
  794. msg_type="detail_result_progress",
  795. )
  796. return True
  797. try:
  798. if is_product_scene == 1:
  799. if product_scene_prompt == "" or product_scene_prompt == None:
  800. raise UnicornException("请填写场景描述")
  801. if is_upper_footer == 1:
  802. if upper_footer_params == {} or upper_footer_params == None:
  803. raise UnicornException("请选择模特")
  804. man_id = upper_footer_params.get("man_id")
  805. if not man_id:
  806. raise UnicornException("请选择男模特")
  807. women_id = upper_footer_params.get("women_id")
  808. if not women_id:
  809. raise UnicornException("请选择女模特")
  810. return_data_check_before_detail = run_main.check_before_detail(config_data)
  811. print("报错前返回的结果数据", return_data_check_before_detail)
  812. if is_product_scene == 1:
  813. goods_dict = parserGoodsDict2Aigc(return_data_check_before_detail)
  814. new_goods_dict = {}
  815. await sendAsyncMessage(
  816. msg="开始处理场景图",
  817. goods_arts=[goods_art_no for goods_art_no in goods_dict.keys()],
  818. status="开始处理",
  819. msg_type="scene_progress",
  820. )
  821. for goods_art_no in goods_dict.keys():
  822. print("处理场景图", goods_art_no)
  823. goods_art_dict_info = goods_dict[goods_art_no]
  824. first_goods_art_no_info = goods_art_dict_info.get("货号资料", [])[0]
  825. first_pics = first_goods_art_no_info.get("pics")
  826. ceshi_image_path = first_pics.get("侧视-抠图")
  827. save_root_path = ceshi_image_path.split("阴影图处理")[0]
  828. save_image_path = f"{save_root_path}场景图.jpg"
  829. if os.path.isfile(save_image_path):
  830. goods_art_dict_info["场景图"] = save_image_path
  831. new_goods_dict[goods_art_no] = goods_art_dict_info
  832. continue
  833. aigc_clazz.center_paste_image(ceshi_image_path, save_image_path)
  834. try:
  835. image_path = aigc_clazz.generateProductScene(
  836. save_image_path, product_scene_prompt, save_image_path
  837. )
  838. # image_path = aigc_clazz.generateProductSceneQW(
  839. # save_image_path, product_scene_prompt, save_image_path
  840. # )
  841. goods_art_dict_info["场景图"] = image_path
  842. new_goods_dict[goods_art_no] = goods_art_dict_info
  843. handler_result.append(
  844. {
  845. "goods_art_no": goods_art_no,
  846. "success": True,
  847. "info": "场景图处理成功",
  848. }
  849. )
  850. await sendAsyncMessage(
  851. msg="场景图处理完成",
  852. goods_arts=[goods_art_no],
  853. status="场景图处理完成",
  854. msg_type="scene_progress",
  855. )
  856. except Exception as e:
  857. os.remove(save_image_path)
  858. handler_result.append(
  859. {
  860. "goods_art_no": goods_art_no,
  861. "success": False,
  862. "info": f"场景图处理失败:{e}",
  863. }
  864. )
  865. await sendAsyncMessage(
  866. msg="场景图处理失败",
  867. goods_arts=[goods_art_no],
  868. status="场景图处理失败",
  869. msg_type="scene_progress",
  870. )
  871. if new_goods_dict is not None or new_goods_dict != {}:
  872. return_data_check_before_detail["data"][
  873. "goods_no_dict"
  874. ] = new_goods_dict
  875. if is_upper_footer == 1:
  876. goods_dict = parserGoodsDict2Aigc(return_data_check_before_detail)
  877. new_goods_dict = {}
  878. await sendAsyncMessage(
  879. msg="开始处理模特图",
  880. goods_arts=list(goods_dict.keys()),
  881. status="开始处理模特图",
  882. msg_type="upper_footer_progress",
  883. )
  884. for goods_art_no in goods_dict.keys():
  885. goods_art_dict_info = goods_dict[goods_art_no]
  886. first_goods_art_no_info = goods_art_dict_info.get("货号资料", [])[0]
  887. first_pics = first_goods_art_no_info.get("pics")
  888. gender = goods_art_dict_info.get("性别")
  889. model_id = man_id if "男" in gender else women_id
  890. ceshi_image_path = first_pics.get("侧视-抠图")
  891. save_root_path = ceshi_image_path.split("阴影图处理")[0]
  892. save_image_path = f"{save_root_path}模特图.jpg"
  893. if os.path.isfile(save_image_path):
  894. goods_art_dict_info["模特图"] = save_image_path
  895. new_goods_dict[goods_art_no] = goods_art_dict_info
  896. continue
  897. shutil.copy(ceshi_image_path, save_image_path)
  898. try:
  899. image_path = aigc_clazz.generateUpperShoes(
  900. save_image_path, model_id, save_image_path
  901. )
  902. # image_path = aigc_clazz.generateModelShoesQW(
  903. # save_image_path, model_id, save_image_path
  904. # )
  905. goods_art_dict_info["模特图"] = image_path
  906. new_goods_dict[goods_art_no] = goods_art_dict_info
  907. handler_result.append(
  908. {
  909. "goods_art_no": goods_art_no,
  910. "success": True,
  911. "info": "模特图处理成功",
  912. }
  913. )
  914. await sendAsyncMessage(
  915. msg="模特图处理成功",
  916. goods_arts=[goods_art_no],
  917. status="模特图处理成功",
  918. msg_type="upper_footer_progress",
  919. )
  920. except Exception as e:
  921. os.remove(save_image_path)
  922. handler_result.append(
  923. {
  924. "goods_art_no": goods_art_no,
  925. "success": False,
  926. "info": f"模特图处理失败:{e}",
  927. }
  928. )
  929. await sendAsyncMessage(
  930. msg="模特图处理失败",
  931. goods_arts=[goods_art_no],
  932. status="模特图处理失败",
  933. msg_type="upper_footer_progress",
  934. )
  935. if new_goods_dict is not None or new_goods_dict != {}:
  936. return_data_check_before_detail["data"][
  937. "goods_no_dict"
  938. ] = new_goods_dict
  939. if is_detail == 0:
  940. # return {
  941. # "code": 0,
  942. # "msg": "",
  943. # "data": {
  944. # "output_folder": handler_result_folder,
  945. # "list": handler_result,
  946. # },
  947. # }
  948. await sendAsyncMessage(
  949. msg="处理结束",
  950. data={"output_folder": handler_result_folder, "list": handler_result},
  951. status="处理结束",
  952. msg_type="detail_result_progress",
  953. )
  954. return True
  955. await sendAsyncMessage(
  956. msg="开始处理详情页",
  957. goods_arts=[],
  958. status="开始处理详情页",
  959. msg_type="detail_progress",
  960. )
  961. check_for_detail_first_res = run_main.check_for_detail_first_call_back(
  962. return_data_check_before_detail
  963. )
  964. if isinstance(check_for_detail_first_res, partial):
  965. result = check_for_detail_first_res()
  966. try:
  967. config_data = result["config_data"]
  968. except:
  969. config_data = result
  970. if config_data["sign_text"] == "已结束详情处理":
  971. await sendAsyncMessage(
  972. msg="详情页处理结束",
  973. goods_arts=[],
  974. status="详情页处理结束",
  975. msg_type="detail_progress",
  976. )
  977. print("config_data", config_data)
  978. out_put_dir = config_data.get("out_put_dir")
  979. if out_put_dir == None:
  980. handler_result_folder = ""
  981. if len(config_data["success_handler"]) > 0:
  982. for good_art in config_data["success_handler"]:
  983. handler_result.append(good_art)
  984. else:
  985. for good_art in goods_art_no_arrays:
  986. handler_result.append(
  987. {
  988. "goods_art_no": good_art,
  989. "success": False,
  990. "info": "处理失败",
  991. }
  992. )
  993. else:
  994. out_put_dir_path = "{}/{}".format(os.getcwd(), out_put_dir).replace(
  995. "\\", "/"
  996. )
  997. handler_result_folder = os.path.dirname(out_put_dir_path)
  998. if len(config_data["success_handler"]) == 0:
  999. for good_art in goods_art_no_arrays:
  1000. handler_result.append(
  1001. {
  1002. "goods_art_no": good_art,
  1003. "success": False,
  1004. "info": "处理失败",
  1005. }
  1006. )
  1007. else:
  1008. if len(online_stores) > 0:
  1009. result_goods_no_dict = return_data_check_before_detail["data"][
  1010. "goods_no_dict"
  1011. ]
  1012. for goods_idx, goods_no_dict in enumerate(
  1013. result_goods_no_dict.keys()
  1014. ):
  1015. all_detail_path_list = config_data["all_detail_path_list"]
  1016. for detail_path in all_detail_path_list:
  1017. if goods_no_dict in detail_path:
  1018. detail_path_replace = detail_path.replace("\\", "/")
  1019. result_goods_no_dict[goods_no_dict][
  1020. "detail_path"
  1021. ] = f"{detail_path_replace}/详情页.jpg"
  1022. await sendAsyncMessage(
  1023. msg="开始上传商品数据",
  1024. goods_arts=[],
  1025. status="开始上传商品数据",
  1026. msg_type="upload_goods_progress",
  1027. )
  1028. try:
  1029. onlineData.uploadGoods2ThirdParty(
  1030. result_goods_no_dict, online_stores=online_stores
  1031. )
  1032. except Exception as e:
  1033. print(f"上传任务出现错误:{e}")
  1034. await sendAsyncMessage(
  1035. msg="商品上传第三方成功",
  1036. goods_arts=[],
  1037. status="商品上传第三方成功",
  1038. msg_type="upload_goods_progress",
  1039. )
  1040. handler_result = config_data["success_handler"]
  1041. else:
  1042. handler_result.append(
  1043. {"goods_art_no": "", "success": False, "info": "处理失败"}
  1044. )
  1045. except UnicornException as e:
  1046. handler_result_folder = ""
  1047. handler_result.append(
  1048. {"goods_art_no": "", "success": False, "info": str(e.msg)}
  1049. )
  1050. print(f"UnicornException 生成错误信息:{e}")
  1051. except Exception as e:
  1052. print(f"详情图生成错误信息:{e}")
  1053. handler_result_folder = ""
  1054. handler_result.append({"goods_art_no": "", "success": False, "info": str(e)})
  1055. await sendAsyncMessage(
  1056. msg="处理结束",
  1057. data={"output_folder": handler_result_folder, "list": handler_result},
  1058. status="处理结束",
  1059. msg_type="detail_result_progress",
  1060. )
  1061. return True
  1062. @app.get("/get_device_tabs", description="获取可执行程序命令列表")
  1063. def get_device_tabs(type: int):
  1064. session = SqlQuery()
  1065. statement = (
  1066. select(DeviceConfigTabs)
  1067. .where(DeviceConfigTabs.mode_type == type)
  1068. .order_by(asc("id"))
  1069. )
  1070. result = session.exec(statement).all()
  1071. session.close()
  1072. sys = CRUD(SysConfigs)
  1073. action_configs = sys.read(session, conditions={"key": "action_configs"})
  1074. session.close()
  1075. return {
  1076. "code": 0,
  1077. "msg": "",
  1078. "data": {"tabs": result, "select_configs": json.loads(action_configs.value)},
  1079. }
  1080. @app.post("/update_tab_name", description="更改tab名称")
  1081. def update_tab_name(params: DeviceConfigTabsReq):
  1082. if params.mode_name == "":
  1083. return {"code": 1, "msg": "名称不能为空", "data": {}}
  1084. session = SqlQuery()
  1085. tabModel = CRUD(DeviceConfigTabs)
  1086. kwargs = {"mode_name": params.mode_name}
  1087. tabModel.updateConditions(session, conditions={"id": params.id}, **kwargs)
  1088. session.close()
  1089. return {
  1090. "code": 0,
  1091. "msg": "",
  1092. "data": None,
  1093. }
  1094. @app.post("/get_device_configs", description="获取可执行程序命令列表")
  1095. def get_device_configs(params: ModelGetDeviceConfig):
  1096. tab_id = params.tab_id
  1097. session = SqlQuery()
  1098. configModel = CRUD(DeviceConfig)
  1099. configList = configModel.read_all(
  1100. session,
  1101. conditions={"tab_id": tab_id},
  1102. order_by="action_index",
  1103. ascending=True,
  1104. )
  1105. return {
  1106. "code": 0,
  1107. "msg": "",
  1108. "data": {"list": configList},
  1109. }
  1110. @app.post("/device_config_detail", description="获取可执行程序详情")
  1111. def device_config_detail(params: ModelGetDeviceConfigDetail):
  1112. action_id = params.id
  1113. session = SqlQuery()
  1114. configModel = CRUD(DeviceConfig)
  1115. model = configModel.read(session, conditions={"id": action_id})
  1116. if model == None:
  1117. return {"code": 1, "msg": "数据不存在", "data": None}
  1118. return {"code": 0, "msg": "", "data": model}
  1119. @app.post("/device_config_detail_query", description="通过条件获取可执行程序详情")
  1120. def device_config_detail_query():
  1121. # tab_id = params.tab_id
  1122. # action_name = params.action_name
  1123. session = SqlQuery()
  1124. sys = CRUD(SysConfigs)
  1125. action_configs = sys.read(session, conditions={"key": "action_configs"})
  1126. action_configs_value = json.loads(action_configs.value)
  1127. left_config = action_configs_value.get("left")
  1128. configModel = CRUD(DeviceConfig)
  1129. model = configModel.read(
  1130. session, conditions={"tab_id": left_config, "action_name": "侧视"}
  1131. )
  1132. if model == None:
  1133. model = configModel.read(session, conditions={"tab_id": left_config})
  1134. return {"code": 0, "msg": "", "data": model}
  1135. @app.post("/remove_config", description="删除一条可执行命令")
  1136. def get_device_configs(params: ModelGetDeviceConfigDetail):
  1137. action_id = params.id
  1138. session = SqlQuery()
  1139. configModel = CRUD(DeviceConfig)
  1140. model = configModel.read(session, conditions={"id": action_id})
  1141. if model == None:
  1142. return {"code": 1, "msg": "数据不存在", "data": None}
  1143. if model.is_system == True:
  1144. return {"code": 1, "msg": "系统配置不允许删除", "data": None}
  1145. configArray = configModel.read_all(session, conditions={"tab_id": model.tab_id})
  1146. if len(configArray) == 1:
  1147. return {"code": 1, "msg": "请至少保留一个配置", "data": None}
  1148. configModel.delete(session, obj_id=action_id)
  1149. return {"code": 0, "msg": "删除成功", "data": None}
  1150. @app.post("/save_device_config", description="创建或修改一条可执行命令")
  1151. def save_device_config(params: SaveDeviceConfig):
  1152. action_id = params.id
  1153. session = SqlQuery()
  1154. deviceConfig = CRUD(DeviceConfig)
  1155. if action_id == None or action_id == 0:
  1156. # 走新增逻辑
  1157. params.id = None
  1158. save_device_config = deviceConfig.create(session, obj_in=params)
  1159. else:
  1160. model = deviceConfig.read(session, conditions={"id": action_id})
  1161. if model == None:
  1162. return {"code": 1, "msg": "数据不存在", "data": None}
  1163. # 走编辑逻辑
  1164. kwargs = params.__dict__
  1165. save_device_config = deviceConfig.update(session, obj_id=action_id, **kwargs)
  1166. return {"code": 0, "msg": "操作成功", "data": save_device_config}
  1167. @app.post("/reset_config", description="创建或修改一条可执行命令")
  1168. def reset_config(params: ModelGetDeviceConfig):
  1169. tab_id = params.tab_id
  1170. if tab_id == None or tab_id == "":
  1171. return {"code": 1, "msg": "参数错误", "data": None}
  1172. session = SqlQuery()
  1173. deviceConfig = CRUD(DeviceConfig)
  1174. first_config = deviceConfig.read(session, conditions={"tab_id": tab_id})
  1175. res = deviceConfig.deleteConditions(session, conditions={"tab_id": tab_id})
  1176. if res is False:
  1177. return {"code": 1, "msg": "操作失败", "data": None}
  1178. actions = json.load(open("action.json", encoding="utf-8"))
  1179. for data in actions:
  1180. data["tab_id"] = tab_id
  1181. data["is_system"] = first_config.is_system
  1182. device_config = DeviceConfig(**data)
  1183. session.add(device_config)
  1184. session.commit()
  1185. # session.close()
  1186. return {"code": 0, "msg": "操作成功", "data": None}
  1187. @app.get("/get_photo_records", description="获取拍照记录")
  1188. def get_photo_records(page: int = 1, size: int = 5):
  1189. session = SqlQuery()
  1190. # photos = CRUD(PhotoRecord)
  1191. print("准备查询拍摄记录", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  1192. statement = (
  1193. select(PhotoRecord)
  1194. .offset((page - 1) * size)
  1195. .limit(size)
  1196. .order_by(desc("id"))
  1197. .group_by("goods_art_no")
  1198. )
  1199. list = []
  1200. result = session.exec(statement).all()
  1201. print("group 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  1202. join_conditions = [
  1203. {
  1204. "model": DeviceConfig,
  1205. "on": PhotoRecord.action_id == DeviceConfig.id,
  1206. "is_outer": False, # 可选,默认False,设为True则为LEFT JOIN
  1207. }
  1208. ]
  1209. for item in result:
  1210. query = (
  1211. select(PhotoRecord, DeviceConfig.action_name)
  1212. .where(PhotoRecord.goods_art_no == item.goods_art_no)
  1213. .join(DeviceConfig, PhotoRecord.action_id == DeviceConfig.id)
  1214. )
  1215. list_item = session.exec(query).mappings().all()
  1216. list.append(
  1217. {
  1218. "goods_art_no": item.goods_art_no,
  1219. "action_time": item.create_time,
  1220. "items": list_item,
  1221. }
  1222. )
  1223. # session.close()
  1224. print("循环查询 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  1225. return {
  1226. "code": 0,
  1227. "msg": "",
  1228. "data": {"list": list, "page": page, "size": size},
  1229. }
  1230. @app.get("/get_last_photo_record", description="获取最后一条拍照记录")
  1231. def get_last_photo_record():
  1232. session = SqlQuery()
  1233. statement = (
  1234. select(PhotoRecord)
  1235. .where(PhotoRecord.image_path != None)
  1236. .order_by(desc("photo_create_time"))
  1237. )
  1238. result = session.exec(statement).first()
  1239. # session.close()
  1240. return {
  1241. "code": 0,
  1242. "msg": "",
  1243. "data": result,
  1244. }
  1245. @app.get("/get_photo_record_detail", description="通过货号获取拍照记录详情")
  1246. def get_photo_record_detail(goods_art_no: str = None):
  1247. if goods_art_no == None:
  1248. return {"code": 1, "msg": "参数错误", "data": None}
  1249. session = SqlQuery()
  1250. photos = CRUD(PhotoRecord)
  1251. items = photos.read_all(session, conditions={"goods_art_no": goods_art_no})
  1252. # session.close()
  1253. return {
  1254. "code": 0,
  1255. "msg": "",
  1256. "data": {"list": items},
  1257. }
  1258. @app.post("/delect_goods_arts", description="通过货号删除记录")
  1259. def delect_goods_arts(params: PhotoRecordDelete):
  1260. session = SqlQuery()
  1261. photos = CRUD(PhotoRecord)
  1262. for item in params.goods_art_nos:
  1263. photos.deleteConditions(session, conditions={"goods_art_no": item})
  1264. # session.close()
  1265. return {
  1266. "code": 0,
  1267. "msg": "操作成功",
  1268. "data": None,
  1269. }
  1270. def query_config_by_key(key_name):
  1271. """
  1272. 在sys_configs.json格式的数据中查询指定的key,如果匹配则返回整个对象
  1273. Args:
  1274. key_name (str): 要查询的key名称
  1275. Returns:
  1276. dict or None: 匹配的对象或None(如果没有找到)
  1277. """
  1278. try:
  1279. # 获取所有配置数据
  1280. configs = json.load(open("sys_configs.json", encoding="utf-8"))
  1281. # 遍历配置数据查找匹配的key
  1282. for config in configs:
  1283. if config.get("key") == key_name:
  1284. return config
  1285. return None
  1286. except Exception as e:
  1287. print(f"查询配置时出错: {e}")
  1288. return None
  1289. @app.get("/get_sys_config", description="查询系统配置")
  1290. def get_sys_config(key: str = None):
  1291. if key == None:
  1292. return {"code": 1, "msg": "参数错误", "data": None}
  1293. session = SqlQuery()
  1294. photos = CRUD(SysConfigs)
  1295. item = photos.read(session, conditions={"key": key})
  1296. search_data = None if item == None else json.loads(item.value)
  1297. if search_data == None:
  1298. sys_config_json = query_config_by_key(key)
  1299. if sys_config_json != None:
  1300. config = SysConfigs(**sys_config_json)
  1301. session.add(config)
  1302. session.commit() # 合并事务提交
  1303. search_data = json.loads(sys_config_json.get("value"))
  1304. return {
  1305. "code": 0,
  1306. "msg": "",
  1307. "data": search_data,
  1308. }
  1309. @app.post("/update_left_right_config", description="更新左右脚配置")
  1310. def update_left_right_config(params: LeftRightParams):
  1311. session = SqlQuery()
  1312. sysConfig = CRUD(SysConfigs)
  1313. model = sysConfig.read(session, conditions={"key": "action_configs"})
  1314. if model == None:
  1315. return {"code": 1, "msg": "配置不存在", "data": None}
  1316. config_value = json.loads(model.value)
  1317. config_value[params.type] = params.id
  1318. update_value = json.dumps(config_value)
  1319. # 走编辑逻辑
  1320. kwargs = {"key": "action_configs", "value": update_value}
  1321. save_device_config = sysConfig.updateConditions(
  1322. session, conditions={"key": "action_configs"}, **kwargs
  1323. )
  1324. return {"code": 0, "msg": "操作成功", "data": None}
  1325. @app.post("/update_record", description="更新拍照记录")
  1326. def update_record(params: RecordUpdate):
  1327. session = SqlQuery()
  1328. photoRecord = CRUD(PhotoRecord)
  1329. model = photoRecord.read(session, conditions={"id": params.id})
  1330. if model == None:
  1331. return {"code": 1, "msg": "记录不存在", "data": None}
  1332. kwargs = params.__dict__
  1333. save_device_config = photoRecord.update(session, obj_id=params.id, **kwargs)
  1334. return {"code": 0, "msg": "操作成功", "data": save_device_config}
  1335. @app.post("/update_sys_configs", description="创建或修改系统配置")
  1336. def save_sys_configs(params: SysConfigParams):
  1337. session = SqlQuery()
  1338. sysConfig = CRUD(SysConfigs)
  1339. model = sysConfig.read(session, conditions={"key": params.key})
  1340. if model == None:
  1341. return {"code": 1, "msg": "配置不存在", "data": None}
  1342. # 走编辑逻辑
  1343. kwargs = params.__dict__
  1344. save_device_config = sysConfig.updateConditions(
  1345. session, conditions={"key": params.key}, **kwargs
  1346. )
  1347. return {"code": 0, "msg": "操作成功", "data": save_device_config}
  1348. @app.post("/create_main_image", description="创建主图测试")
  1349. def create_main_image(params: MaineImageTest):
  1350. file_path = params.file_path
  1351. onePic = OnePicTest(pic_path=file_path)
  1352. main_out_path = onePic.HandlerMainImage()
  1353. return {"code": 0, "msg": "操作成功", "data": {"main_out_path": main_out_path}}
  1354. def insertEmptyLogoList(session):
  1355. """插入空logo列表"""
  1356. data = {"key": "logo_configs", "value": "[]"}
  1357. config = SysConfigs(**data)
  1358. session.add(config)
  1359. session.commit()
  1360. session.close()
  1361. item = SysConfigs()
  1362. item.key = "logo_configs"
  1363. item.value = "[]"
  1364. return item
  1365. @app.get("/logo_list", description="logo列表")
  1366. def logo_list():
  1367. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  1368. check_path(logo_dir)
  1369. logo_files = os.listdir(logo_dir)
  1370. logo_list = []
  1371. for logoItem in logo_files:
  1372. logo_list.append(f"{logo_dir}{logoItem}")
  1373. return {"code": 0, "msg": "操作成功", "data": logo_list}
  1374. @app.post("/add_logo", description="添加logo")
  1375. def add_logo(params: LogoParams):
  1376. logo_path = params.logo_path.replace("\\", "/")
  1377. session = SqlQuery()
  1378. sysConfig = CRUD(SysConfigs)
  1379. item = sysConfig.read(session, conditions={"key": "logo_configs"})
  1380. if item == None:
  1381. item = insertEmptyLogoList(session)
  1382. if os.path.isfile(logo_path) == False:
  1383. return {"code": 1, "msg": "logo文件不存在", "data": None}
  1384. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  1385. check_path(logo_dir)
  1386. fpath, fname = os.path.split(logo_path)
  1387. logo_path_info = logo_dir + fname
  1388. shutil.copy(logo_path, logo_path_info) # 复制文件
  1389. logo_files = os.listdir(logo_dir)
  1390. logo_list = []
  1391. for logoItem in logo_files:
  1392. logo_list.append(f"{logo_dir}{logoItem}")
  1393. return {
  1394. "code": 0,
  1395. "msg": "",
  1396. "data": {"logo": logo_path_info},
  1397. }
  1398. @app.post("/delete_logo", description="删除logo")
  1399. def delete_logo(params: LogoParamsupdate):
  1400. logo_path = params.path
  1401. if os.path.isfile(logo_path) == False:
  1402. return {"code": 1, "msg": "logo文件不存在", "data": None}
  1403. os.remove(logo_path)
  1404. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  1405. check_path(logo_dir)
  1406. logo_files = os.listdir(logo_dir)
  1407. logo_list = []
  1408. for logoItem in logo_files:
  1409. logo_list.append(f"{logo_dir}{logoItem}")
  1410. return {"code": 0, "msg": "操作成功", "data": logo_list}
  1411. @app.post("/close_other_window", description="关闭窗口")
  1412. def close_other_window():
  1413. hwnd_list = []
  1414. def callback(hwnd, _):
  1415. title = GetWindowText(hwnd)
  1416. if title == "digiCamControl by Duka Istvan":
  1417. hwnd_list.append(hwnd)
  1418. EnumWindows(callback, None)
  1419. if hwnd_list:
  1420. hwnd = hwnd_list[0]
  1421. win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
  1422. return {"code": 0, "msg": "关闭成功", "data": {"status": True}}
  1423. return {"code": 0, "msg": "关闭失败", "data": {"status": False}}
  1424. def syncUserJsonConfigs(token):
  1425. hlm_token = token
  1426. headers = {
  1427. "Authorization": f"Bearer {hlm_token}",
  1428. "content-type": "application/json",
  1429. }
  1430. url = settings.DOMAIN + "/api/ai_image/camera_machine/get_all_user_configs"
  1431. result = requests.get(url=url, headers=headers)
  1432. sys_configs = result.json().get("data", {}).get("configs")
  1433. session = SqlQuery()
  1434. sysConfigs = CRUD(SysConfigs)
  1435. if sys_configs:
  1436. sysConfigs.deleteConditions(session, {})
  1437. configList = []
  1438. for config_keys in sys_configs.keys():
  1439. sys_configs[config_keys]
  1440. configList.append(
  1441. {
  1442. "key": config_keys,
  1443. "value": json.dumps(sys_configs[config_keys], ensure_ascii=False),
  1444. }
  1445. )
  1446. batch_insert_sys_configs(session, configList)
  1447. @app.post("/sync_sys_configs", description="同步线上配置到本地")
  1448. def sync_sys_configs(params: SyncLocalConfigs):
  1449. hlm_token = params.token
  1450. headers = {
  1451. "Authorization": f"Bearer {hlm_token}",
  1452. "content-type": "application/json",
  1453. }
  1454. url = settings.DOMAIN + "/api/ai_image/camera_machine/get_all_user_configs"
  1455. result = requests.get(url=url, headers=headers)
  1456. sys_configs = result.json().get("data", {}).get("configs")
  1457. session = SqlQuery()
  1458. sysConfigs = CRUD(SysConfigs)
  1459. if sys_configs:
  1460. sysConfigs.deleteConditions(session, {})
  1461. configList = []
  1462. for config_keys in sys_configs.keys():
  1463. sys_configs[config_keys]
  1464. configList.append(
  1465. {
  1466. "key": config_keys,
  1467. "value": json.dumps(sys_configs[config_keys], ensure_ascii=False),
  1468. }
  1469. )
  1470. batch_insert_sys_configs(session, configList)
  1471. else:
  1472. all_configs = sysConfigs.read_all(session)
  1473. localConfigData = {}
  1474. for local_config in all_configs:
  1475. localConfigData[local_config.key] = json.loads(local_config.value)
  1476. data_json = json.dumps({"configs": localConfigData}, ensure_ascii=False)
  1477. # 同步本地到线上
  1478. url = settings.DOMAIN + "/api/ai_image/camera_machine/update_all_user_configs"
  1479. requests.post(url=url, headers=headers, data=data_json)
  1480. return {"code": 0, "msg": "操作成功", "data": None}
  1481. @app.post("/sync_actions", description="同步左右脚配置到本地")
  1482. def sync_action_configs(params: SyncLocalConfigs):
  1483. hlm_token = params.token
  1484. headers = {
  1485. "Authorization": f"Bearer {hlm_token}",
  1486. "content-type": "application/json",
  1487. }
  1488. url = settings.DOMAIN + "/api/ai_image/camera_machine/get_all_user_tabs"
  1489. result = requests.get(url=url, headers=headers)
  1490. session = SqlQuery()
  1491. deviceConfigs = CRUD(DeviceConfig)
  1492. deviceConfigTabs = CRUD(DeviceConfigTabs)
  1493. tabs = result.json().get("data", {}).get("tabs")
  1494. actions = result.json().get("data", {}).get("actions")
  1495. if tabs:
  1496. # 先删除再创建
  1497. deviceConfigTabs.deleteConditions(session, {})
  1498. deviceConfigs.deleteConditions(session, {})
  1499. batch_insert_device_configsNew(session, tabs, actions)
  1500. else:
  1501. all_actions = deviceConfigs.read_all(session)
  1502. all_tabs = deviceConfigTabs.read_all(session)
  1503. all_tabs_json = [item.model_dump(mode='json') for item in all_tabs]
  1504. all_actions_json = [item.model_dump(mode="json") for item in all_actions]
  1505. data_json = json.dumps(
  1506. {"tabs": all_tabs_json, "actions": all_actions_json}, ensure_ascii=False
  1507. )
  1508. sync_url = settings.DOMAIN + "/api/ai_image/camera_machine/sync_actions"
  1509. result = requests.post(url=sync_url, headers=headers, data=data_json)
  1510. tabs = result.json().get("data", {}).get("tabs")
  1511. actions = result.json().get("data", {}).get("actions")
  1512. insert_action_ids = result.json().get("data", {}).get("insert_action_ids")
  1513. if tabs:
  1514. deviceConfigTabs.deleteConditions(session, {})
  1515. deviceConfigs.deleteConditions(session, {})
  1516. batch_insert_device_configsNew(session, tabs, actions)
  1517. if insert_action_ids:
  1518. for action_item in insert_action_ids:
  1519. photos = CRUD(PhotoRecord)
  1520. old_id = action_item.get("old_id")
  1521. new_id = action_item.get("new_id")
  1522. kwargs = {"action_id": new_id}
  1523. photos.updateConditionsAll(
  1524. session, conditions={"action_id": old_id}, **kwargs
  1525. )
  1526. # 因为左右脚线上id可能会发生变化 所以需要重新同步一下本地得配置信息
  1527. # syncUserJsonConfigs(hlm_token)
  1528. return {"code": 0, "msg": "操作成功", "data": None}