270 lines
13 KiB
Python
270 lines
13 KiB
Python
from ctypes import util
|
||
import os, oss2, time, redis, requests, shutil, sys, subprocess, json, platform
|
||
from PIL import Image, ImageDraw, ImageFont
|
||
from retrying import retry
|
||
import atexit,platform
|
||
if platform.system() == 'Windows':
|
||
sys.path.append('e:\\libs\\')
|
||
import common
|
||
def find_blender_bin_path():
|
||
if platform.system() == 'Linux': return '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):
|
||
# 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}/'
|
||
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
|
||
find = False
|
||
for file in filelist:
|
||
filename = file.key.split('/')[-1]
|
||
if filename == '': continue
|
||
if filename.endswith(f'{pid}.obj'):
|
||
find = True
|
||
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 and print_type == 3:
|
||
for file in os.listdir(path):
|
||
if file.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文件,异常退出')
|
||
sys.exit(1)
|
||
|
||
# print('下载完成后静默10秒,等待文件写入完成')
|
||
# time.sleep(10)
|
||
|
||
def getPidFromOrderId(orderId):
|
||
getPidFromOrderId_url = 'https://mp.api.suwa3d.com/api/printOrder/info'
|
||
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 make3d4print_task(r):
|
||
try:
|
||
if r.llen('model:printOrder') == 0:
|
||
time.sleep(5)
|
||
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 = r.lpop('model:printOrder')
|
||
if orderId is None: return
|
||
orderId = orderId.decode('utf-8')
|
||
res = getPidFromOrderId(orderId)
|
||
if res == -1:
|
||
print("查询打印订单信息失败,重新开启进程")
|
||
os.system(f'python auto_convert3d.py')
|
||
return
|
||
pid = str(res['pid'])
|
||
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', )
|
||
down_obj_fromoss(pid, print_type, orderId)
|
||
# 获取程序运行当前目录
|
||
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文件生成异常,退出')
|
||
sys.exit(1)
|
||
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}')
|
||
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}')
|
||
for file in os.listdir(path):
|
||
# 跳过一些不需要上传的文件
|
||
if file in [f'{pid}.png', f'{pid}.obj', f'{pid}_decimate.glb', f'{pid}_decimate.obj',f'{pid}.mtl', f'{pid}_decimate.mtl', f'{pid}Tex1_decimate.jpg', f'{pid}_original.obj', f'{pid}_original.mtl']: continue
|
||
|
||
# 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')
|
||
|
||
def team_check(r):
|
||
try:
|
||
if r.llen('model:IndependentRepairTeamcheckGLBQueue') == 0:
|
||
time.sleep(5)
|
||
return
|
||
except Exception as e:
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 'redis连接异常,5秒后重试')
|
||
print(e)
|
||
time.sleep(5)
|
||
r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6)
|
||
return
|
||
repair_id = r.lpop('model:IndependentRepairTeamcheckGLBQueue')
|
||
if repair_id is None: return
|
||
repair_id = repair_id.decode('utf-8')
|
||
|
||
res = requests.get(f'{getRepairInfo_url}?id={repair_id}')
|
||
print(f'getRepairInfo_url:{getRepairInfo_url}?id={repair_id}')
|
||
print(res.text)
|
||
pid = res.json()['data']['pid']
|
||
pid = str(pid)
|
||
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} repair_id:{repair_id} 生成团队审核模型 start model:IndependentRepairTeamcheckGLBQueue', )
|
||
down_obj_fromoss(pid)
|
||
obj_filename = f'{pid}.obj'
|
||
glb_filename = f'{pid}.glb'
|
||
print('开始转换obj文件为glb文件...')
|
||
os.system(f'gltfpack -c -i {os.path.join(workdir, "print", pid, obj_filename)} -o {os.path.join(workdir, "print", pid, glb_filename)} -vt 16 -vc 16')
|
||
#os.system(f'FBX2glTF -i {os.path.join(workdir, "print", pid, obj_filename)} -o {os.path.join(workdir, "print", pid, glb_filename)}')
|
||
#如果压缩后的glb文件小于2M,文件贴图异常,需要重新生成,直到成功
|
||
# while os.path.getsize(os.path.join(workdir, "print", pid, glb_filename)) < 2 * 1024 * 1024:
|
||
# print(f'{pid}glb文件大小:{os.path.getsize(os.path.join(workdir, "print", pid, glb_filename))}')
|
||
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 压缩后的glb文件小于2M,文件贴图异常,重新生成glb文件')
|
||
# # 将有异常的pid相关文件全部移动到异常文件夹,然后重新下载重新生成
|
||
# if not os.path.exists(os.path.join(workdir, 'print', 'error', pid)):
|
||
# os.makedirs(os.path.join(workdir, 'print', 'error', pid))
|
||
# for file in os.listdir(os.path.join(workdir, 'print', pid)):
|
||
# shutil.move(os.path.join(workdir, 'print', pid, file), os.path.join(workdir, 'print', 'error', pid, file))
|
||
# down_obj_fromoss(pid)
|
||
# os.system(f'gltfpack -c -i {os.path.join(workdir, "print", pid, obj_filename)} -o {os.path.join(workdir, "print", pid, glb_filename)}')
|
||
|
||
print('上传glb文件到oss...')
|
||
oss_client.put_object_from_file(f'glbs/print/{glb_filename}', os.path.join(workdir, "print", pid, glb_filename))
|
||
|
||
print(f'{update_repair_status_url}?id={repair_id}')
|
||
res = requests.get(f'{update_repair_status_url}?id={repair_id}')
|
||
print('更新团队审核状态:', res.text)
|
||
shutil.rmtree(os.path.join(workdir, 'print', pid), ignore_errors=True)
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} 生成团队审核模型 end')
|
||
|
||
def platform_check(r):
|
||
try:
|
||
if r.llen('model:modelRepairGLBQueue') == 0:
|
||
time.sleep(5)
|
||
return
|
||
except Exception as e:
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 'redis连接异常,5秒后重试')
|
||
print(e)
|
||
time.sleep(5)
|
||
r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6)
|
||
return
|
||
pid = r.lpop('model:modelRepairGLBQueue')
|
||
if pid is None: return
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} 生成平台审核模型 start', )
|
||
|
||
pid = pid.decode('utf-8')
|
||
down_obj_fromoss(pid)
|
||
obj_filename = f'{pid}.obj'
|
||
glb_filename = f'{pid}.glb'
|
||
os.system(f'gltfpack -c -i {os.path.join(workdir, "print", pid, obj_filename)} -o {os.path.join(workdir, "print", pid, glb_filename)}')
|
||
oss_client.put_object_from_file(f'glbs/print/{glb_filename}', os.path.join(workdir, "print", pid, glb_filename))
|
||
|
||
print(f'{update_check_url}?id={pid}')
|
||
res = requests.get(f'{update_check_url}?id={pid}')
|
||
print(res.text)
|
||
shutil.rmtree(os.path.join(workdir, 'print', pid), ignore_errors=True)
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} 生成平台审核模型 end')
|
||
|
||
|
||
#obj文件转成 glb文件
|
||
def objToGlbAndUpload(pid):
|
||
obj_filename = f'{pid}_original.obj'
|
||
glb_filename = f'{pid}.glb'
|
||
print('开始转换obj文件为glb文件...')
|
||
os.system(f'gltfpack -c -i {os.path.join(workdir, "print", pid, obj_filename)} -o {os.path.join(workdir, "print", pid, glb_filename)}')
|
||
#重命名产生的glb 文件
|
||
|
||
print('上传glb文件到oss...')
|
||
oss_client.put_object_from_file(f'glbs/print/{glb_filename}', os.path.join(workdir, "print", pid, glb_filename))
|
||
|
||
|
||
def main(r):
|
||
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), '模型生成程序 start')
|
||
while True:
|
||
team_check(r)
|
||
# platform_check(r)
|
||
#make3d4print_task(r)
|
||
|
||
if __name__ == '__main__':
|
||
atexit.register(common.notify,"R13-修模师审核通过,生成打印任务程序停止")
|
||
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.api.suwa3d.com/api/customerP3dLog/updateStatusToWaitingPlatformCheckingStatus'
|
||
update_team_check_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/updateStatusToWaitingTeamCheckingStatus'
|
||
update_status_printstatus_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/updateBuildPrintModelStatus'
|
||
update_makeprintobj_status_url = 'https://mp.api.suwa3d.com/api/printOrder/updateMakePrintObjSucceed'
|
||
getRepairInfo_url = 'https://repair.api.suwa3d.com/api/modelRepairOrder/teamCheckGLBInfo'
|
||
update_repair_status_url = 'https://repair.api.suwa3d.com/api/modelRepairOrder/updateStatusToWaitingTeamCheckingStatus'
|
||
if platform.system() == 'Windows':
|
||
workdir = 'D:\\'
|
||
else:
|
||
workdir = '/data/datasets/'
|
||
|
||
blenderbin = find_blender_bin_path()
|
||
|
||
r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6)
|
||
main(r) |