Browse Source

Refactor main.py to enable API call for updating slice status and enhance argument parsing. Update funcs.py for improved code readability and error handling in Blender execution.

master
dongchangxi 3 weeks ago
parent
commit
d43a50e14d
  1. 25
      script/factory_sliceing_v2/main.py
  2. 264
      script/factory_sliceing_v2/utils/funcs.py

25
script/factory_sliceing_v2/main.py

@ -3,6 +3,7 @@ import redis
import oss2,time,sys import oss2,time,sys
import requests import requests
import argparse,json import argparse,json
from utils.funcs import requestApiToUpdateSliceStatus
# 将当前脚本所在目录添加到 Python 路径,以便导入 utils 模块 # 将当前脚本所在目录添加到 Python 路径,以便导入 utils 模块
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
@ -50,14 +51,14 @@ def step1(versionId):
objCounts += 1 objCounts += 1
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 下载处理完成的obj文件数量: {objCounts}') print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 下载处理完成的obj文件数量: {objCounts}')
# requestApiToUpdateSliceStatus(versionId,objCounts) requestApiToUpdateSliceStatus(versionId,objCounts)
# 读取 队列中一个数据出来 # 读取 队列中一个数据出来
def main(work_dir=None): def main(work_dir=None):
global currentDir
# 如果指定了工作目录,使用指定的目录 # 如果指定了工作目录,使用指定的目录
if work_dir: if work_dir:
work_dir = os.path.abspath(work_dir) work_dir = os.path.abspath(work_dir)
@ -122,13 +123,13 @@ def testMain():
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 处理完成,res={res}') print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 处理完成,res={res}')
if __name__ == '__main__': if __name__ == '__main__':
testMain() #testMain()
# parser = argparse.ArgumentParser(description='排版打印订单处理程序') parser = argparse.ArgumentParser(description='排版打印订单处理程序')
# parser.add_argument( parser.add_argument(
# '--work-dir', '--work-dir',
# type=str, type=str,
# default=None, default=None,
# help='指定工作目录(磁盘路径),例如: D:/work 或 /Users/username/work。如果不指定,则使用脚本所在目录' help='指定工作目录(磁盘路径),例如: D:/work 或 /Users/username/work。如果不指定,则使用脚本所在目录'
# ) )
# args = parser.parse_args() args = parser.parse_args()
# main(work_dir=args.work_dir) main(work_dir=args.work_dir)

264
script/factory_sliceing_v2/utils/funcs.py

@ -1,14 +1,18 @@
import requests,time import requests
import os,platform import time
import os
import platform
import shutil import shutil
import json import json
import shlex import shlex
import subprocess
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
from .oss_redis import ossClient from .oss_redis import ossClient
from .logs import log from .logs import log
from .oss_func import download_file_with_check, checkFileExists from .oss_func import download_file_with_check, checkFileExists
from .changeFiles import changeObjFile, changeMtlFile from .changeFiles import changeObjFile, changeMtlFile
from .small_machine_transform import transform_save from .small_machine_transform import transform_save
ENV = 'prod' ENV = 'prod'
url = 'https://mp.api.suwa3d.com' url = 'https://mp.api.suwa3d.com'
if ENV == 'dev': if ENV == 'dev':
@ -17,11 +21,11 @@ elif ENV == 'prod':
url = 'https://mp.api.suwa3d.com' url = 'https://mp.api.suwa3d.com'
#根据打印ID 获取下载目录 # 根据打印ID 获取下载目录
def getDownloadDirByPrintId(printIds): def getDownloadDirByPrintId(printIds):
#调用接口获取下载的路径 # 调用接口获取下载的路径
api_url = f"{url}/api/printOrder/getInfoByPrintIds" api_url = f"{url}/api/printOrder/getInfoByPrintIds"
res = requests.post(api_url,json={"print_ids":printIds}) res = requests.post(api_url, json={"print_ids": printIds})
res = res.json() res = res.json()
print(f"根据打印ID 获取下载目录, res={res}") print(f"根据打印ID 获取下载目录, res={res}")
if res["code"] == 1000: if res["code"] == 1000:
@ -29,9 +33,10 @@ def getDownloadDirByPrintId(printIds):
else: else:
return False return False
#根据批次id,进行切片中的状态变更
def requestApiToUpdateSliceStatus(versionId,downloadCounts): # 根据批次id,进行切片中的状态变更
api_url = f"{url}/api/printTypeSettingOrder/updateBatchSliceing?batch_id={versionId}&download_counts="+str(downloadCounts) def requestApiToUpdateSliceStatus(versionId, downloadCounts):
api_url = f"{url}/api/printTypeSettingOrder/updateBatchSliceing?batch_id={versionId}&download_counts=" + str(downloadCounts)
log(f'发起状态变更请求url={api_url}, versionId={versionId}') log(f'发起状态变更请求url={api_url}, versionId={versionId}')
try: try:
# 添加超时参数,防止请求时间过长 # 添加超时参数,防止请求时间过长
@ -48,39 +53,40 @@ def requestApiToUpdateSliceStatus(versionId,downloadCounts):
log(f'状态变更请求异常, error={str(e)}') log(f'状态变更请求异常, error={str(e)}')
return False return False
#判断是否上传了 JSON 文件
# 判断是否上传了 JSON 文件
def checkJsonFileExists(versionId): def checkJsonFileExists(versionId):
log(f"检测文件和图片是否存在, versionId={versionId}") log(f"检测文件和图片是否存在, versionId={versionId}")
jsonFilePath = f'batchPrint/{versionId}/{versionId}.json' jsonFilePath = f'batchPrint/{versionId}/{versionId}.json'
#判断oss 上是否存在 # 判断oss 上是否存在
jpgFilePath = f'batchPrint/{versionId}/{versionId}.jpg' jpgFilePath = f'batchPrint/{versionId}/{versionId}.jpg'
if not ossClient().object_exists(jsonFilePath): if not ossClient().object_exists(jsonFilePath):
log(f'JSON文件不存在: {jsonFilePath}') log(f'JSON文件不存在: {jsonFilePath}')
return False,False return False, False
if not ossClient().object_exists(jpgFilePath): if not ossClient().object_exists(jpgFilePath):
log(f'JPG文件不存在: {jpgFilePath}') log(f'JPG文件不存在: {jpgFilePath}')
return False,False return False, False
log(f"文件和图片检测成功,存在, versionId={versionId}") log(f"文件和图片检测成功,存在, versionId={versionId}")
return jsonFilePath,jpgFilePath return jsonFilePath, jpgFilePath
# 检测本地文件是否存在
#检测本地文件是否存在
def checkLocalFileExists(localFilePath): def checkLocalFileExists(localFilePath):
if not os.path.exists(localFilePath): if not os.path.exists(localFilePath):
return False return False
return True return True
#读取JSON文件内容
# 读取JSON文件内容
def readJsonFile(localFilePath): def readJsonFile(localFilePath):
with open(localFilePath, 'r', encoding='utf-8') as f: with open(localFilePath, 'r', encoding='utf-8') as f:
jsonData = json.load(f) jsonData = json.load(f)
return jsonData return jsonData
#根据批次ID,获取批次信息
# 根据批次ID,获取批次信息
def getBatchInfo(versionId): def getBatchInfo(versionId):
url1 = f"{url}/api/printTypeSettingOrder/getBatchInfoAndPrintMachineInfoByBatchId?batch_id={versionId}" url1 = f"{url}/api/printTypeSettingOrder/getBatchInfoAndPrintMachineInfoByBatchId?batch_id={versionId}"
res = requests.get(url1) res = requests.get(url1)
@ -91,13 +97,14 @@ def getBatchInfo(versionId):
else: else:
return False return False
#下载文件,读取文件内容,并且文件迁移至正确的目录里,不再放在临时目录里
def downloadJsonAndJpgFileAndMoveToCorrectDir(versionId,currentDir): # 下载文件,读取文件内容,并且文件迁移至正确的目录里,不再放在临时目录里
jsonFilePath,jpgFilePath = checkJsonFileExists(versionId) def downloadJsonAndJpgFileAndMoveToCorrectDir(versionId, currentDir):
jsonFilePath, jpgFilePath = checkJsonFileExists(versionId)
if jsonFilePath == False or jpgFilePath == False: if jsonFilePath == False or jpgFilePath == False:
return False,False return False, False
#将文件下载到临时目录,待会要判断是否什么类型机型 # 将文件下载到临时目录,待会要判断是否什么类型机型
tempDir = os.path.join(currentDir, 'batchPrint', 'temp', versionId) tempDir = os.path.join(currentDir, 'batchPrint', 'temp', versionId)
if not os.path.exists(tempDir): if not os.path.exists(tempDir):
os.makedirs(tempDir) os.makedirs(tempDir)
@ -106,74 +113,73 @@ def downloadJsonAndJpgFileAndMoveToCorrectDir(versionId,currentDir):
ok = download_file_with_check(jsonFilePath, localFilePath) ok = download_file_with_check(jsonFilePath, localFilePath)
if not ok: if not ok:
log(f"JSON 文件下载失败或不完整, versionId={versionId}") log(f"JSON 文件下载失败或不完整, versionId={versionId}")
return False,False return False, False
#下载JPG文件 # 下载JPG文件
localJpgFilePath = os.path.join(tempDir, f'{versionId}.jpg') localJpgFilePath = os.path.join(tempDir, f'{versionId}.jpg')
ok = download_file_with_check(jpgFilePath, localJpgFilePath) ok = download_file_with_check(jpgFilePath, localJpgFilePath)
if not ok: if not ok:
log(f"JPG 文件下载失败或不完整, versionId={versionId}") log(f"JPG 文件下载失败或不完整, versionId={versionId}")
return False,False return False, False
#根据批次ID,获取批次信息和打印机信息 # 根据批次ID,获取批次信息和打印机信息
batchMachineInfo = getBatchInfo(versionId) batchMachineInfo = getBatchInfo(versionId)
if not batchMachineInfo: if not batchMachineInfo:
log(f"获取批次信息和打印机信息失败, versionId={versionId}") log(f"获取批次信息和打印机信息失败, versionId={versionId}")
return False,False return False, False
# "batch_info": batchInfo, # "batch_info": batchInfo,
# "print_machine_info": printMachineInfo, # "print_machine_info": printMachineInfo,
machineInfo = batchMachineInfo["print_machine_info"] machineInfo = batchMachineInfo["print_machine_info"]
print(f"machineInfo={machineInfo['id']}") print(f"machineInfo={machineInfo['id']}")
dirNewName = "" dirNewName = ""
if str(machineInfo["machine_type"]) == '1': if str(machineInfo["machine_type"]) == '1':
dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_small_No'+str(machineInfo['id'])) dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_small_No' + str(machineInfo['id']))
else: else:
dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_big_No'+str(machineInfo['id'])) dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_big_No' + str(machineInfo['id']))
#判断目录是否存在,存在就删除 # 判断目录是否存在,存在就删除
if os.path.exists(dirNewName): if os.path.exists(dirNewName):
shutil.rmtree(dirNewName) shutil.rmtree(dirNewName)
#创建目录 # 创建目录
os.makedirs(dirNewName) os.makedirs(dirNewName)
#创建json子目录 # 创建json子目录
jsonSubDir = os.path.join(dirNewName, 'json') jsonSubDir = os.path.join(dirNewName, 'json')
if not os.path.exists(jsonSubDir): if not os.path.exists(jsonSubDir):
os.makedirs(jsonSubDir) os.makedirs(jsonSubDir)
# 将数据移动过来
#将数据移动过来
shutil.move(localFilePath, os.path.join(jsonSubDir, '3DPrintLayout.json')) shutil.move(localFilePath, os.path.join(jsonSubDir, '3DPrintLayout.json'))
shutil.move(localJpgFilePath, os.path.join(jsonSubDir, f'{versionId}.jpg')) shutil.move(localJpgFilePath, os.path.join(jsonSubDir, f'{versionId}.jpg'))
#检测文件是否移动成功 # 检测文件是否移动成功
if not os.path.exists(os.path.join(jsonSubDir, '3DPrintLayout.json')): if not os.path.exists(os.path.join(jsonSubDir, '3DPrintLayout.json')):
log(f"JSON文件不存在, versionId={versionId}") log(f"JSON文件不存在, versionId={versionId}")
return False,False return False, False
if not os.path.exists(os.path.join(jsonSubDir, f'{versionId}.jpg')): if not os.path.exists(os.path.join(jsonSubDir, f'{versionId}.jpg')):
log(f"JPG文件不存在, versionId={versionId}") log(f"JPG文件不存在, versionId={versionId}")
return False,False return False, False
log(f"文件移动成功, versionId={versionId}") log(f"文件移动成功, versionId={versionId}")
#返回目录路径 # 返回目录路径
return dirNewName,machineInfo return dirNewName, machineInfo
#整合json文件,读取对应的数据,返回数据结构 # 整合json文件,读取对应的数据,返回数据结构
def getJsonData(dirNewName): def getJsonData(dirNewName):
jsonFilePath = os.path.join(dirNewName, 'json', '3DPrintLayout.json') jsonFilePath = os.path.join(dirNewName, 'json', '3DPrintLayout.json')
if not os.path.exists(jsonFilePath): if not os.path.exists(jsonFilePath):
log(f"JSON文件不存在, dirNewName={dirNewName}") log(f"JSON文件不存在, dirNewName={dirNewName}")
return False return False
#读取JSON文件内容 # 读取JSON文件内容
jsonData = readJsonFile(jsonFilePath) jsonData = readJsonFile(jsonFilePath)
#读取models # 读取models
models = jsonData.get('models', []) models = jsonData.get('models', [])
if not models: if not models:
log(f"models不存在, dirNewName={dirNewName}") log(f"models不存在, dirNewName={dirNewName}")
return False return False
listData = [] listData = []
#遍历models # 遍历models
for model in models: for model in models:
file_name = model.get('file_name', '') file_name = model.get('file_name', '')
#分割数据 # 分割数据
arrFileName = file_name.split('_') arrFileName = file_name.split('_')
orderId = arrFileName[0] orderId = arrFileName[0]
pid = arrFileName[1] pid = arrFileName[1]
@ -181,14 +187,12 @@ def getJsonData(dirNewName):
size = arrFileName[3] size = arrFileName[3]
counts = arrFileName[4].replace("x", "").replace(".obj", "") counts = arrFileName[4].replace("x", "").replace(".obj", "")
#检测这些数据 # 检测这些数据
if not orderId or not pid or not printId or not size or not counts: if not orderId or not pid or not printId or not size or not counts:
log(f"数据不完整, orderId={orderId}, pid={pid}, printId={printId}, size={size}, counts={counts}") log(f"数据不完整, orderId={orderId}, pid={pid}, printId={printId}, size={size}, counts={counts}")
return False return False
# 创建数据结构
#创建数据结构
modelInfo = { modelInfo = {
"orderId": orderId, "orderId": orderId,
"printId": printId, "printId": printId,
@ -198,27 +202,27 @@ def getJsonData(dirNewName):
"file_name": file_name, "file_name": file_name,
} }
listData.append(modelInfo) listData.append(modelInfo)
#检测数据长度 # 检测数据长度
if len(listData) == 0: if len(listData) == 0:
log(f"数据长度为0, dirNewName={dirNewName}") log(f"数据长度为0, dirNewName={dirNewName}")
return False return False
#返回数据结构 # 返回数据结构
return listData return listData
# 读取 json 文件,获取 homo_matrix 数据,根据 file_name 获取 homo_matrix 数据 # 读取 json 文件,获取 homo_matrix 数据,根据 file_name 获取 homo_matrix 数据
def getHomoMatrixByFileName(dirNewName,fileName): def getHomoMatrixByFileName(dirNewName, fileName):
jsonFilePath = os.path.join(dirNewName, 'json', '3DPrintLayout.json') jsonFilePath = os.path.join(dirNewName, 'json', '3DPrintLayout.json')
if not os.path.exists(jsonFilePath): if not os.path.exists(jsonFilePath):
log(f"JSON文件不存在, dirNewName={dirNewName}") log(f"JSON文件不存在, dirNewName={dirNewName}")
return False return False
#读取JSON文件内容 # 读取JSON文件内容
jsonData = readJsonFile(jsonFilePath) jsonData = readJsonFile(jsonFilePath)
if not jsonData: if not jsonData:
log(f"读取JSON文件内容失败, dirNewName={dirNewName}") log(f"读取JSON文件内容失败, dirNewName={dirNewName}")
return False return False
for model in jsonData["models"]: for model in jsonData["models"]:
log(f"jsonData={model['file_name']} == {fileName}") log(f"jsonData={model['file_name']} == {fileName}")
if model["file_name"] == fileName: if model["file_name"] == fileName:
@ -227,7 +231,7 @@ def getHomoMatrixByFileName(dirNewName,fileName):
return False return False
#处理单个数据项:下载文件、修改关联路径、转换数据(如果是小机台) # 处理单个数据项:下载文件、修改关联路径、转换数据(如果是小机台)
def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine): def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine):
""" """
处理单个数据项的函数用于多线程处理 处理单个数据项的函数用于多线程处理
@ -247,10 +251,10 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
if str(tempv["print_order_id"]) == str(v["printId"]): if str(tempv["print_order_id"]) == str(v["printId"]):
info = tempv info = tempv
break break
if not info: if not info:
return False, f"未找到匹配的下载路径信息, printId={v['printId']}" return False, f"未找到匹配的下载路径信息, printId={v['printId']}"
filePath = info["path"] filePath = info["path"]
pid = info["pid"] pid = info["pid"]
orderId = info["order_id"] orderId = info["order_id"]
@ -258,8 +262,8 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
size = info["real_size"] size = info["real_size"]
counts = info["quantity"] counts = info["quantity"]
fileName = v["file_name"] fileName = v["file_name"]
#判断文件是否存在 # 判断文件是否存在
ossJpgFilePath = f"{filePath}/printId_{printId}Tex1.jpg" ossJpgFilePath = f"{filePath}/printId_{printId}Tex1.jpg"
if not checkFileExists(ossJpgFilePath): if not checkFileExists(ossJpgFilePath):
ossJpgFilePath = f"{filePath}/{pid}Tex1.jpg" ossJpgFilePath = f"{filePath}/{pid}Tex1.jpg"
@ -272,12 +276,13 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
{"ossPath": f"{filePath}/{pid}.obj", "localPath": os.path.join(dirPath, localObjName)}, {"ossPath": f"{filePath}/{pid}.obj", "localPath": os.path.join(dirPath, localObjName)},
{"ossPath": f"{filePath}/{pid}.mtl", "localPath": os.path.join(dirPath, loaclMtlName)}, {"ossPath": f"{filePath}/{pid}.mtl", "localPath": os.path.join(dirPath, loaclMtlName)},
] ]
#遍历下载文件 # 遍历下载文件
beginTime = time.time() beginTime = time.time()
objsLocal = "" objsLocal = ""
for objFiles in arrDownloadFiles: for objFiles in arrDownloadFiles:
#判断 mtl 和 jpg 文件是否存在,存在就不在下载了 downloadBeginTime = time.time()
# 判断 mtl 和 jpg 文件是否存在,存在就不在下载了
if "mtl" in objFiles["localPath"] or "jpg" in objFiles["localPath"]: if "mtl" in objFiles["localPath"] or "jpg" in objFiles["localPath"]:
if os.path.exists(objFiles["localPath"]): if os.path.exists(objFiles["localPath"]):
continue continue
@ -288,18 +293,20 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
log(error_msg) log(error_msg)
return False, error_msg return False, error_msg
#下载成功之后要修改文件之间的关联路径 log(f"下载文件耗时: {time.time() - downloadBeginTime}秒 - {objFiles['localPath']}")
# 下载成功之后要修改文件之间的关联路径
if objFiles["localPath"].endswith(".obj"): if objFiles["localPath"].endswith(".obj"):
beginChangeTime = time.time()
objsLocal = objFiles["localPath"] objsLocal = objFiles["localPath"]
changeObjFile(objFiles["localPath"], f"{orderId}_{pid}.mtl") changeObjFile(objFiles["localPath"], f"{orderId}_{pid}.mtl")
log(f"修改obj关联耗时: {time.time() - beginChangeTime}秒 - {objFiles['localPath']}")
if objFiles["localPath"].endswith(".mtl"): if objFiles["localPath"].endswith(".mtl"):
changeMtlFile(objFiles["localPath"], f"{orderId}_{pid}Tex1.jpg") changeMtlFile(objFiles["localPath"], f"{orderId}_{pid}Tex1.jpg")
endTime = time.time() endTime = time.time()
log(f"下载文件和修改文件之间的关联路径 : 耗时{endTime - beginTime}秒 - {fileName}") log(f"下载文件和修改文件之间的关联路径 : 耗时{endTime - beginTime}秒 - {fileName}")
#如果是小机台,则要转换数据 # 如果是小机台,则要转换数据
if isSmallMachine: if isSmallMachine:
timeBegin = time.time() timeBegin = time.time()
homo_matrix = getHomoMatrixByFileName(dirNewName, localObjName) homo_matrix = getHomoMatrixByFileName(dirNewName, localObjName)
@ -308,27 +315,65 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
log(error_msg) log(error_msg)
return False, error_msg return False, error_msg
#通过blender 调用执行 python 文件 # 通过blender 调用执行 python 文件
blender_bin_path = findBpyModule() blender_bin_path = findBpyModule()
# 获取 small_machine_transform.py 的绝对路径 # 获取 small_machine_transform.py 的绝对路径
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
transform_script_path = os.path.join(script_dir, 'small_machine_transform.py') transform_script_path = os.path.join(script_dir, 'small_machine_transform.py')
# 将 homo_matrix 转换为 JSON 字符串,并对路径进行转义
# 将 homo_matrix 转换为 JSON 字符串
homo_matrix_json = json.dumps(homo_matrix) homo_matrix_json = json.dumps(homo_matrix)
# 使用 shlex.quote 来安全地转义路径和参数
transform_script_path_quoted = shlex.quote(transform_script_path) # 构建命令参数列表(使用列表形式,避免 shell 转义问题)
objsLocal_quoted = shlex.quote(objsLocal) cmd = [
homo_matrix_quoted = shlex.quote(homo_matrix_json) blender_bin_path,
error = os.system(f"{blender_bin_path} -b -P {transform_script_path_quoted} -- --objPathName={objsLocal_quoted} --trans={homo_matrix_quoted}") '--background',
if error != 0: '--python',
error_msg = f"调用blender 执行 python 文件失败, error={error}, fileName={fileName}" transform_script_path,
'--',
f'--objPathName={objsLocal}',
f'--trans={homo_matrix_json}'
]
log(f"执行 Blender 命令: {' '.join(cmd[:4])} ... (参数已隐藏)")
try:
# 使用 subprocess 执行命令,捕获输出和错误
# 在 Windows 上,Blender 输出可能是 UTF-8,需要指定编码并处理错误
result = subprocess.run(
cmd,
capture_output=True,
text=True,
encoding='utf-8', # 指定 UTF-8 编码
errors='replace', # 遇到无法解码的字符时替换为占位符,而不是抛出异常
timeout=300, # 5分钟超时
check=False # 不自动抛出异常,手动检查返回码
)
if result.returncode != 0:
error_output = result.stderr if result.stderr else result.stdout
error_msg = f"调用blender 执行 python 文件失败, error={result.returncode}, fileName={fileName}"
if error_output:
error_msg += f", 错误信息: {error_output[:500]}" # 限制错误信息长度
log(error_msg)
return False, error_msg
log(f"调用blender 执行 python 文件成功, fileName={fileName}")
if result.stdout:
log(f"Blender 输出: {result.stdout[:200]}") # 记录部分输出用于调试
except subprocess.TimeoutExpired:
error_msg = f"调用blender 执行超时(超过5分钟), fileName={fileName}"
log(error_msg)
return False, error_msg
except Exception as e:
error_msg = f"调用blender 执行时发生异常: {str(e)}, fileName={fileName}"
log(error_msg) log(error_msg)
return False, error_msg return False, error_msg
log(f"调用blender 执行 python 文件成功, error={error}, fileName={fileName}")
timeEnd = time.time() timeEnd = time.time()
log(f"转换数据时间: 耗时{timeEnd - timeBegin}秒 - {objsLocal}") log(f"转换数据时间: 耗时{timeEnd - timeBegin}秒 - {objsLocal}")
return True, "" return True, ""
except Exception as e: except Exception as e:
error_msg = f"处理数据项时发生异常, fileName={v.get('file_name', 'unknown')}, error={str(e)}" error_msg = f"处理数据项时发生异常, fileName={v.get('file_name', 'unknown')}, error={str(e)}"
@ -336,13 +381,13 @@ def _process_single_item(v, arrDownloadPath, dirNewName, dirPath, isSmallMachine
return False, error_msg return False, error_msg
#json文件进行下载对应的数据 和转换数据,传递目录路径 # json文件进行下载对应的数据 和转换数据,传递目录路径
def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False, max_workers=10): def downloadDataByOssAndTransformSave(dirNewName, isSmallMachine=False, max_workers=1):
listData = getJsonData(dirNewName) listData = getJsonData(dirNewName)
if not listData: if not listData:
log(f"获取数据失败, dirNewName={dirNewName}") log(f"获取数据失败, dirNewName={dirNewName}")
return False return False
#遍历数据 # 遍历数据
arrPrintId = [] arrPrintId = []
arrPrintDataInfo = [] arrPrintDataInfo = []
for modelInfo in listData: for modelInfo in listData:
@ -352,28 +397,28 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False, max_worke
"file_name": modelInfo.get('file_name'), "file_name": modelInfo.get('file_name'),
}) })
#调用接口获取下载的路径 # 调用接口获取下载的路径
arrDownloadPath = getDownloadDirByPrintId(arrPrintId) arrDownloadPath = getDownloadDirByPrintId(arrPrintId)
if not arrDownloadPath: if not arrDownloadPath:
log(f"获取下载路径失败, arrPrintId={arrPrintId}") log(f"获取下载路径失败, arrPrintId={arrPrintId}")
return False return False
dirPath = os.path.join(dirNewName, 'data') dirPath = os.path.join(dirNewName, 'data')
if not os.path.exists(dirPath): if not os.path.exists(dirPath):
os.makedirs(dirPath) os.makedirs(dirPath)
#使用多线程并发处理数据 # 使用多线程并发处理数据
log(f"开始多线程处理数据, 共{len(listData)}个项目, 线程数={max_workers}") log(f"开始多线程处理数据, 共{len(listData)}个项目, 线程数={max_workers}")
beginTime = time.time() beginTime = time.time()
# 使用线程池并发处理 # 使用线程池并发处理
with ThreadPoolExecutor(max_workers=max_workers) as executor: with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交所有任务 # 提交所有任务
future_to_item = { future_to_item = {
executor.submit(_process_single_item, v, arrDownloadPath, dirNewName, dirPath, isSmallMachine): v executor.submit(_process_single_item, v, arrDownloadPath, dirNewName, dirPath, isSmallMachine): v
for v in listData for v in listData
} }
# 收集结果 # 收集结果
success_count = 0 success_count = 0
fail_count = 0 fail_count = 0
@ -392,27 +437,48 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False, max_worke
fail_count += 1 fail_count += 1
error_msg = f"处理数据项时发生异常: {str(e)}" error_msg = f"处理数据项时发生异常: {str(e)}"
log(f"处理异常: {v.get('file_name', 'unknown')}, 错误: {error_msg} ({fail_count}/{len(listData)})") log(f"处理异常: {v.get('file_name', 'unknown')}, 错误: {error_msg} ({fail_count}/{len(listData)})")
endTime = time.time() endTime = time.time()
log(f"多线程处理完成, 总耗时{endTime - beginTime}秒, 成功:{success_count}, 失败:{fail_count}, 总计:{len(listData)}") log(f"多线程处理完成, 总耗时{endTime - beginTime}秒, 成功:{success_count}, 失败:{fail_count}, 总计:{len(listData)}")
# 如果有任何失败,返回 False # 如果有任何失败,返回 False
if fail_count > 0: if fail_count > 0:
log(f"部分任务处理失败,共{fail_count}个失败") log(f"部分任务处理失败,共{fail_count}个失败")
return False return False
return True return True
def findBpyModule(): def findBpyModule():
# 返回 Blender 可执行文件路径(macOS) # 返回 Blender 可执行文件路径
blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender' blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender'
# 判断当前是 windows 还是 macOS # 判断当前是 windows 还是 macOS
if platform.system() == 'Windows': if platform.system() == 'Windows':
blender_bin_path = 'C:\\Program Files\\Blender Foundation\\Blender 5.0\\blender.exe' # Windows 上常见的 Blender 安装路径
possible_paths = [
'C:\\Program Files\\Blender Foundation\\Blender 5.0\\blender.exe',
'C:\\Program Files\\Blender Foundation\\Blender 4.4\\blender.exe',
'C:\\Program Files\\Blender Foundation\\Blender 4.3\\blender.exe',
'C:\\Program Files\\Blender Foundation\\Blender 4.2\\blender.exe',
'C:\\Program Files\\Blender Foundation\\Blender 4.1\\blender.exe',
'C:\\Program Files\\Blender Foundation\\Blender 4.0\\blender.exe',
]
# 查找存在的路径
for path in possible_paths:
if os.path.exists(path):
blender_bin_path = path
break
else:
# 如果都没找到,使用默认路径
blender_bin_path = 'C:\\Program Files\\Blender Foundation\\Blender 5.0\\blender.exe'
log(f"警告: 未找到 Blender 可执行文件,使用默认路径: {blender_bin_path}")
else: else:
blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender' blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender'
# 检查路径是否存在
if not os.path.exists(blender_bin_path):
error_msg = f"Blender 可执行文件不存在: {blender_bin_path}"
log(error_msg)
raise FileNotFoundError(error_msg)
return blender_bin_path
return blender_bin_path

Loading…
Cancel
Save