from ctypes import util import os, oss2, time, redis, requests, shutil, sys, subprocess, json, platform,random from PIL import Image, ImageDraw, ImageFont from retrying import retry import atexit,platform import get_preview_image # if platform.system() == 'Windows': # sys.path.append('libs\\') sys.path.append('/home/acprint/code/libs/') import common #创建文本文件 def creatDoingLog(order_id): #在指定路径创建一条 order_id.txt 文本 file_path = f"doingLog/{order_id}.txt" if os.path.exists(file_path): return #创建 with open(file_path, "w", encoding="utf-8") as file: file.write("1") #移除指定的文本文件 def removeDoingLog(order_id): file_path = f"doingLog/{order_id}.txt" if not os.path.exists(file_path): return os.remove(file_path) #遍历文件夹,返回指定的order_id def get_order_id_by_txt(): #遍历文件夹 for file in os.listdir("doingLog"): if file != "": arrFile = file.split(".") return arrFile[0] return None def find_blender_bin_path(): if platform.system() == 'Linux': return '/home/acprint/code/blender/blender' base_path = 'C:\\Program Files\\Blender Foundation\\' if os.path.exists(base_path): for dir in os.listdir(base_path): if dir.startswith('Blender'): blender_bin_path = base_path + dir + '\\blender.exe' return f'"{blender_bin_path}"' else: print('未找到blender安装目录') exit(1) @retry(stop_max_attempt_number=10, wait_fixed=3000) def down_obj_fromoss(pid, print_type=1, order_id=None,download_flag="print_build"): # print_type:// 打印状态 1:正常打印 2:重打 3:加打,4: 样品 print('开始下载obj文件...' , pid) if not order_id is None: path = os.path.join(workdir, 'print', f'{pid}_{order_id}') else: path = os.path.join(workdir, 'print', pid) if not os.path.exists(path): os.makedirs(path) # 根据前缀获取文件列表 prefix = f'objs/print/{pid}/' #根据order_id 获取文件在 oss 上的存储路径 if order_id is not None: tempURL = "https://mp.gray.api.suwa3d.com/api/order/getOssSuffixByOrderId?orderId="+str(order_id) res = requests.get(tempURL) resCode = res.json()['code'] if int(resCode) != 1000: return -1 print(res.text) if res.json()['data'] != "": prefix = f'objs/print/{pid}/{res.json()["data"]}/{str(order_id)}/' filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix) #判断是否有值,没有值的话就从老的路径再获取一次数据 if len(filelist) == 0: filelist = oss2.ObjectIteratorV2(oss_client, prefix=f'objs/print/{pid}/') find = False findTex1Jpg = False for file in filelist: filename = file.key.split('/')[-1] if filename == '': continue if filename.endswith(f'{pid}.obj'): find = True if download_flag == "print_build": if filename != str(pid)+".obj" and filename != str(pid)+".mtl" and filename != str(pid)+"Tex1.jpg" and filename != str(pid)+"_RB_B_Tex1.jpg": continue localfile = os.path.join(path, filename) res = oss_client.get_object_to_file(file.key, localfile) print(f'下载文件:{file.key},状态:{res.status}') if not find: filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix) for file in filelist: filename = file.key.split('/')[-1] if filename == '': continue if filename.endswith(f'.obj'): find = True # if download_flag == "print_build": # if filename != str(pid)+".obj" and filename != str(pid)+".mtl" and filename != str(pid)+"Tex1.jpg": # continue localfile = os.path.join(path, filename) res = oss_client.get_object_to_file(file.key, localfile) print(f'下载文件:{file.key},状态:{res.status}') break if find: os.rename(localfile, os.path.join(path,f"{pid}.obj")) #重命名文件 #判断是否有Tex1.jpg if not os.path.exists(os.path.join(path,f"{pid}Tex1.jpg")): filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix) for file in filelist: filename = file.key.split('/')[-1] if filename == '': continue if filename.endswith(f'{pid}.jpg'): findTex1Jpg = True # if download_flag == "print_build": # if filename != str(pid)+".obj" and filename != str(pid)+".mtl" and filename != str(pid)+"Tex1.jpg": # continue localfile = os.path.join(path, filename) res = oss_client.get_object_to_file(file.key, localfile) print(f'下载文件:{file.key},状态:{res.status}') break if findTex1Jpg: os.rename(localfile, os.path.join(path,f"{pid}Tex1.jpg")) #重命名文件 # for file in filelist: # filename = file.key.split('/')[-1] # if filename == '': continue # if filename.endswith(f'{pid}.obj'): # find = True # if filename.endswith('.obj'): # print('找到其他obj文件,采用这个文件来生成需要的尺寸', file) # shutil.copy(os.path.join(path, file), os.path.join(path, f'{pid}.obj')) # find = True # break if not find: print('找不到obj文件,跳过') common.notify(f"{pid}-构建打印文件,找不到obj文件,异常,跳过该任务处理") # sys.exit(1) os.system(f'python auto_convert3d.py') return # print('下载完成后静默10秒,等待文件写入完成') # time.sleep(10) #根据pid获取orderId def getPidFromOrderId(orderId): getPidFromOrderId_url = 'https://mp.gray.api.suwa3d.com/api/printOrder/infoByOrderId' print(f'{getPidFromOrderId_url}?id={orderId}') res = requests.get(f'{getPidFromOrderId_url}?id={orderId}') resCode = res.json()['code'] if int(resCode) != 1000: return -1 print(res.text) return res.json()['data'] def detect_obj4print(pid, orderId): for file in os.listdir(os.path.join(workdir, 'print', f'{pid}_{orderId}')): if file.endswith('.obj') and 'x' in file: return True def restart_current_process(new_command): try: # 保存新进程的命令 command = new_command.split() # 启动新进程 new_process = subprocess.Popen(command) # 打印新进程的PID print(f"New process started with PID: {new_process.pid}") # 终止当前进程 os._exit(0) except Exception as e: print(f"An error occurred: {e}") def make3d4print_task(r): tempOrderId = "0" try: if r.llen('model:printOrder') == 0: time.sleep(5) # tempOrderId = get_order_id_by_txt() # if tempOrderId == "0": # return except Exception as e: print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 'redis连接异常,重新连接') print(e) time.sleep(5) r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6) return orderId = None if tempOrderId == "0": orderId = r.lpop('model:printOrder') else: orderId = tempOrderId if orderId is None: return if type(orderId) != str: orderId = orderId.decode('utf-8') # orderId = 56077 res = getPidFromOrderId(orderId) if res == -1: print("查询打印订单信息失败,重新开启进程") #os.system(f'python auto_convert3d.py') return #根据 buy_type 判断 是否是冰箱贴 或者徽章 buyType = str(res['buy_type']) if buyType == "2" or buyType == "3": #塞入到no_resize 队列 r.lpush("model:noresize", orderId) return pid = str(res['pid']) if pid == "88985": return if pid == "": return #创建正在处理的文本内容 creatDoingLog(orderId) print_type = res['print_type'] digital_type = res['digital_type'] # 0: 只有手办 1: 只有数字模型 2: 手办+数字模型 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 生成待打印模型 start', ) isFindObj = False down_obj_fromoss(pid, print_type, orderId,download_flag="print_build") # 获取程序运行当前目录 resize_py_path = os.path.join(os.getcwd(), 'blender', 'resize_model.py') print(f'{blenderbin} -b -P {resize_py_path} -- {orderId}') os.system(f'{blenderbin} -b -P {resize_py_path} -- {orderId}') if not detect_obj4print(pid, orderId): print('obj文件生成异常,退出,重新执行') restart_current_process("python auto_convert3d.py") return print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 生成待打印模型 end') print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 处理鼻孔 start') if os.path.exists(f'{workdir}/print/{pid}_{orderId}/{pid}Tex1_old.jpg'): print('已经处理过鼻孔,跳过') else: os.system(f'python fix_nose.py {pid}_{orderId}') #上传jpg文件 #oss_client.put_object_from_file(f'objs/print/{pid}/{pid}Tex1.jpg', os.path.join(workdir, 'print', f'{pid}_{orderId}', f'{pid}Tex1.jpg')) # oss_client.put_object_from_file(f'objs/print/{pid}/{pid}Tex1_old.jpg', os.path.join(workdir, 'print', f'{pid}_{orderId}', f'{pid}Tex1_old.jpg')) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 处理鼻孔 end') # print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 生成脚底板二维码 start') # os.system(f'{blenderbin} -b -P d:\\apps\\blender\\auto_dm.py -- {pid}_{orderId}') # print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 生成脚底板二维码 end') print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 上传生成的模型 start') path = os.path.join(workdir, 'print', f'{pid}_{orderId}') # 如果指定文件夹目标文件存在,则先删除 if os.path.exists(os.path.join(workdir, f'complate/objs/{pid}/order_{orderId}/')): delete_files_in_directory(os.path.join(workdir, f'complate/objs/{pid}/order_{orderId}/')) for file in os.listdir(path): # 跳过一些不需要上传的文件 if file in [f'{pid}.png',f'{pid}_old.jpg', f'{pid}.obj', f'{pid}_decimate.glb', f'{pid}_decimate.obj', f'{pid}_decimate.mtl', f'{pid}Tex1_decimate.jpg', f'{pid}_original.obj', f'{pid}_original.mtl']: continue print("当前目录",os.path.join(path, file)) print(f"复制文件路径-{file}") #将文件移动到指定目录 if not os.path.exists(os.path.join(workdir, f'complate/objs/{pid}/')): os.makedirs(os.path.join(workdir, f'complate/objs/{pid}/'),mode=0o777, exist_ok=True) if not os.path.exists(os.path.join(workdir, f'complate/objs/{pid}/order_{orderId}/')): os.makedirs(os.path.join(workdir, f'complate/objs/{pid}/order_{orderId}/'),mode=0o777, exist_ok=True) shutil.move(os.path.join(path, file), os.path.join(workdir, f'complate/objs/{pid}/order_{orderId}/')) # oss_client.put_object_from_file(f'objs/print/{pid}/{file}', os.path.join(path, file)) # texture_file = os.path.join(path, f'{pid}Tex1_decimate.jpg') # if os.path.exists(texture_file): # img = Image.open(texture_file) # img = img.resize((int(img.size[0] * 0.5), int(img.size[1] * 0.5))) # img.save(texture_file, quality=90, optimize=True) # print('resize texture file to 50% success') input = os.path.join(path, f'{pid}_decimate.obj') output = os.path.join(path, f'{pid}_decimate.glb') # os.system(f'gltfpack -c -i {input} -o {output}') # oss_client.put_object_from_file(f'glbs/3d/{pid}.glb', output) shutil.rmtree(path, ignore_errors=True) print(f'{update_makeprintobj_status_url}?id={orderId}') if digital_type == 1: print('只有数字模型,不需要推送手办打印任务,仍有调用接口') res = requests.get(f'{update_makeprintobj_status_url}?id={orderId}') print('更新打印状态:', res.text) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'orderId:{orderId} pid:{pid} 上传生成的模型 end') removeDoingLog(orderId) #生成封面图片 print('小票封面图处理中....') get_preview_image.createImage(pid) #os.system(f'python get_preview_image.py {pid}') print(f"{pid}-已处理结束") restart_current_process("python auto_convert3d.py") def delete_files_in_directory(directory): for file_name in os.listdir(directory): file_path = os.path.join(directory, file_name) try: if os.path.isfile(file_path): os.remove(file_path) print(f"Deleted: {file_path}") except Exception as e: print(f"Error deleting {file_path}: {e}") def create_redis_connection(): """创建 Redis 连接,若连接失败则重试""" while True: try: r = redis.Redis(host="mark.api.suwa3d.com", password="kcV2000", port=6379, db=6) # 尝试进行一次操作,检查连接是否有效 r.ping() # ping 操作是一个简单的连接测试 print("Redis连接成功!") return r except ConnectionError: print("Redis连接失败,正在重试...") time.sleep(5) def main(r): print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), '模型生成程序 start') while True: try: #构建打印文件 make3d4print_task(r) except Exception as e: print(f'出现异常:{e}') time.sleep(15) r = create_redis_connection() continue if __name__ == '__main__': # atexit.register(common.notify,"虚拟机,生成打印任务程序停止") AccessKeyId = 'LTAI5tSReWm8hz7dSYxxth8f' AccessKeySecret = '8ywTDF9upPAtvgXtLKALY2iMYHIxdS' Endpoint = 'oss-cn-shanghai.aliyuncs.com' Bucket = 'suwa3d-securedata' oss_client = oss2.Bucket(oss2.Auth(AccessKeyId, AccessKeySecret), Endpoint, Bucket) update_check_url = 'https://mp.gray.api.suwa3d.com/api/customerP3dLog/updateStatusToWaitingPlatformCheckingStatus' update_team_check_url = 'https://mp.gray.api.suwa3d.com/api/customerP3dLog/updateStatusToWaitingTeamCheckingStatus' update_status_printstatus_url = 'https://mp.gray.api.suwa3d.com/api/customerP3dLog/updateBuildPrintModelStatus' update_makeprintobj_status_url = 'https://mp.gray.api.suwa3d.com/api/printOrder/updateMakePrintObjSucceed' getRepairInfo_url = 'https://repair.gray.api.suwa3d.com/api/modelRepairOrder/teamCheckGLBInfo' update_repair_status_url = 'https://repair.gray.api.suwa3d.com/api/modelRepairOrder/updateStatusToWaitingTeamCheckingStatus' if platform.system() == 'Windows': workdir = 'E:\\' else: workdir = '/data/datasets/' blenderbin = find_blender_bin_path() r = create_redis_connection() #E:\\complate/objs/147852_54579/ # os.remove(os.path.join(workdir, f'complate/objs/147852_54579/')) main(r)