import os import shutil import time from pathlib import Path import traceback import uuid import random import string import argparse # 导入各个步骤需要的函数 from project2json.project_converter import convert_project_to_json from transform_expense_preview import process_directory from supplement_kg import costsummary_upwards from equipment_calculation.main import bcl_calculate from cost_comparison import compare_costs_batch import tempfile # 基础目录 BASE_DIR = "project2json" TEMP_DIR = tempfile.gettempdir() # 使用临时目录 # 生成随机8位ID def generate_session_id(): return "".join(random.choices(string.ascii_uppercase + string.digits, k=8)) # 创建会话工作目录(仅会话根目录) def create_session_directories(session_id): # 仅创建会话根目录用于容纳每个文件的独立GUID临时目录 session_root = os.path.join(BASE_DIR, "outputs", session_id) os.makedirs(session_root, exist_ok=True) return { "session_root": session_root, } # 为单个上传文件创建独立的GUID临时目录,包含六个子目录 def create_file_workdirs(session_id): file_guid = uuid.uuid4().hex root = os.path.join(BASE_DIR, "outputs", session_id, file_guid) dirs = { "root": root, "upload_dir": os.path.join(root, "uploads"), # 生成json前的上传文件夹 "bcl_dir": os.path.join(root, "bcl"), # bcl计算文件文件夹(备用,当前流程未直接使用) "json_dir": os.path.join(root, "json"), # 生成后的json文件夹 "merged_dir": os.path.join(root, "merged"), "bcl_results_dir": os.path.join(root, "bclresults"), "final_dir": os.path.join(root, "final"), } for d in dirs.values(): os.makedirs(d, exist_ok=True) return dirs # 整合的转化流程函数(无前端),执行步骤1到步骤3,并将步骤3.2/4替换为 compare_costs_batch def convert_all_steps(files): """处理传入的工程文件列表,输出成功执行的文件数量。 流程: 1) 保存上传 -> 转JSON 2) 处理JSON结构并费用向上汇总(merged_dir) 3) BCL计算(输出到 bcl_results_dir) 4) 调用 compare_costs_batch(bcl_results_dir, project_json) 进行费用对比 """ try: session_id = generate_session_id() print(f"生成会话ID: {session_id}") session_dirs = create_session_directories(session_id) session_root = session_dirs["session_root"] total_files = len(files) if files else 0 if total_files == 0: print("未选择任何文件。") return 0 total_success = 0 for idx, file in enumerate(files, start=1): try: file_name = os.path.basename(file if isinstance(file, str) else file.name) print(f"[{idx}/{total_files}] 处理文件: {file_name}") # 创建该文件的独立GUID临时目录 fdirs = create_file_workdirs(session_id) upload_dir = fdirs["upload_dir"] json_dir = fdirs["json_dir"] merged_dir = fdirs["merged_dir"] bcl_results_dir = fdirs["bcl_results_dir"] # 步骤1.1: 保存上传的该文件 save_path = os.path.join(upload_dir, file_name) shutil.copy(file if isinstance(file, str) else file.name, save_path) # 步骤1.2: 转换为JSON success, file_num = convert_project_to_json(upload_dir, json_dir, fdirs["bcl_dir"]) if not success: raise RuntimeError("转换为JSON失败") # 步骤1.3: 处理JSON文件结构 process_directory(json_dir) # 步骤2: 费用向上汇总 result_step2 = costsummary_upwards(json_dir, merged_dir) if not result_step2: print("警告:未生成任何汇总JSON") # 步骤3.1: 计算工程量取费表 bcl_calculate(merged_dir, bcl_results_dir, bcl_dir_path=fdirs["bcl_dir"]) # 选择项目JSON:从 merged_dir 中选择一个主 JSON(若多个则取第一个) merged_jsons = [ os.path.join(merged_dir, f) for f in os.listdir(merged_dir) if f.lower().endswith(".json") ] if not merged_jsons: raise FileNotFoundError("在 merged_dir 中未找到项目 JSON") project_data_json_path = merged_jsons[0] # 步骤3.2/4: 调用 compare_costs_batch 进行费用对比 compare_costs_batch(bcl_results_dir, project_data_json_path) total_success += 1 except Exception as fe: print(f"处理文件 {file_name} 失败: {fe}\n{traceback.format_exc()}") print(f"成功执行 {total_success} 个文件。") return total_success except Exception as e: error_msg = f"执行流程出错: {str(e)}\n{traceback.format_exc()}" print(error_msg) return 0 # ========= 批处理与命令行入口(文件末尾追加) ========= def create_named_workdirs(output_base_dir: str, base_name: str): """在输出根目录下创建 '<工程名>+' 的工作目录结构。""" guid = uuid.uuid4().hex root_name = f"{base_name}+{guid}" root = os.path.join(output_base_dir, root_name) dirs = { "root": root, "upload_dir": os.path.join(root, "uploads"), "bcl_dir": os.path.join(root, "bcl"), "json_dir": os.path.join(root, "json"), "merged_dir": os.path.join(root, "merged"), "bcl_results_dir": os.path.join(root, "bclresults"), "final_dir": os.path.join(root, "final"), } for d in dirs.values(): os.makedirs(d, exist_ok=True) return dirs def run_batch_with_io(input_dir: str, output_dir: str) -> int: """批量处理输入目录下的工程文件,输出到指定的输出根目录。""" input_dir = os.path.abspath(input_dir) output_dir = os.path.abspath(output_dir) os.makedirs(output_dir, exist_ok=True) candidates = [ os.path.join(input_dir, f) for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f)) ] if not candidates: print(f"输入目录无文件: {input_dir}") return 0 total_success = 0 for idx, file_path in enumerate(candidates, start=1): base_name = os.path.basename(file_path) stem = os.path.splitext(base_name)[0] print(f"[{idx}/{len(candidates)}] 处理文件: {base_name}") try: # 1) 为该工程创建独立工作区 fdirs = create_named_workdirs(output_dir, stem) upload_dir = fdirs["upload_dir"] json_dir = fdirs["json_dir"] merged_dir = fdirs["merged_dir"] bcl_results_dir = fdirs["bcl_results_dir"] bcl_dir = fdirs["bcl_dir"] # 2) 保存上传 save_path = os.path.join(upload_dir, base_name) shutil.copy(file_path, save_path) # 3) 转换为JSON(并将 BCL 最佳版本复制到 bcl_dir) success, _file_num = convert_project_to_json(upload_dir, json_dir, bcl_dir) if not success: raise RuntimeError("转换为JSON失败") # 4) 处理JSON结构 process_directory(json_dir) # 5) 费用向上汇总 result_step2 = costsummary_upwards(json_dir, merged_dir) if not result_step2: print("警告:未生成任何汇总JSON") # 6) 计算工程量取费表(读取 bcl_dir,输出到 bcl_results_dir) bcl_calculate(merged_dir, bcl_results_dir, bcl_dir_path=bcl_dir) # 7) 选择一个项目 JSON 进行费用对比 merged_jsons = [os.path.join(merged_dir, f) for f in os.listdir(merged_dir) if f.lower().endswith(".json")] if not merged_jsons: raise FileNotFoundError("在 merged_dir 中未找到项目 JSON") project_data_json_path = merged_jsons[0] # 8) 费用对比 compare_costs_batch(bcl_results_dir, project_data_json_path) total_success += 1 except Exception as fe: print(f"处理文件 {base_name} 失败: {fe}\n{traceback.format_exc()}") print(f"成功执行 {total_success}/{len(candidates)} 个文件。输出根目录: {output_dir}") return total_success if __name__ == "__main__": input_dir = r"data/input" # 请修改为你的实际输入路径 output_dir = r"data/output" # 请修改为你的实际输出路径 t0 = time.time() try: count = run_batch_with_io(input_dir, output_dir) print(f"\n🎉 ✅ 处理完成,共成功 {count} 个。耗时: {int(time.time() - t0)} 秒") except Exception as e: print(f"\n❌ 执行失败: {e}\n{traceback.format_exc()}") raise