分模候选方案
This commit is contained in:
@@ -299,3 +299,78 @@ class CalculationService:
|
||||
}
|
||||
|
||||
return detailed_cavity_json
|
||||
|
||||
@classmethod
|
||||
def build_plan_result(
|
||||
cls,
|
||||
geometry_data: Dict[str, Any],
|
||||
material: Dict[str, Any],
|
||||
file_path: str,
|
||||
plan_result: Optional[Dict[str, Any]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""构建多方案分模结果,并保留单方案兼容字段。"""
|
||||
if not plan_result or not plan_result.get("candidate_schemes"):
|
||||
legacy = cls.build_detailed_cavity_json(
|
||||
geometry_data=geometry_data,
|
||||
material=material,
|
||||
file_path=file_path,
|
||||
cavity_mesh_data=None,
|
||||
)
|
||||
return {
|
||||
"best_scheme_id": "scheme_1",
|
||||
"candidate_schemes": [
|
||||
{
|
||||
"scheme_id": "scheme_1",
|
||||
"rank": 1,
|
||||
"title": "推荐方案",
|
||||
"method": "legacy_fallback",
|
||||
"score": 60.0,
|
||||
"score_breakdown": {},
|
||||
"summary": "当前模型未生成多方案,返回兼容单方案结果",
|
||||
"parting": {
|
||||
"axis": legacy.get("metadata", {}).get("parting_direction", "Z"),
|
||||
"direction": None,
|
||||
"surface": legacy.get("parting_surface", {}),
|
||||
"line": [],
|
||||
},
|
||||
"cavity_data": legacy,
|
||||
"key_info": legacy.get("mold_cavities", {}).get("cavity_key_info", {}),
|
||||
"undercut_regions": legacy.get("undercut_regions", []),
|
||||
"side_actions": legacy.get("side_actions", {}),
|
||||
}
|
||||
],
|
||||
"global_summary": {
|
||||
"scheme_count": 1,
|
||||
"recommended_reason": "兼容旧版单方案结果",
|
||||
},
|
||||
"cavity_data": legacy,
|
||||
"key_info": legacy.get("mold_cavities", {}).get("cavity_key_info", {}),
|
||||
}
|
||||
|
||||
candidate_schemes = plan_result.get("candidate_schemes", [])
|
||||
best_scheme = cls.get_best_scheme(plan_result)
|
||||
result = {
|
||||
"best_scheme_id": plan_result.get("best_scheme_id"),
|
||||
"candidate_schemes": candidate_schemes,
|
||||
"global_summary": plan_result.get("global_summary", {}),
|
||||
"cavity_data": best_scheme.get("cavity_data", {}) if best_scheme else {},
|
||||
"key_info": best_scheme.get("key_info", {}) if best_scheme else {},
|
||||
}
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_best_scheme(plan_result: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
|
||||
if not plan_result:
|
||||
return None
|
||||
|
||||
schemes = plan_result.get("candidate_schemes", [])
|
||||
if not schemes:
|
||||
return None
|
||||
|
||||
best_scheme_id = plan_result.get("best_scheme_id")
|
||||
if best_scheme_id:
|
||||
for scheme in schemes:
|
||||
if scheme.get("scheme_id") == best_scheme_id:
|
||||
return scheme
|
||||
|
||||
return schemes[0]
|
||||
|
||||
@@ -15,6 +15,7 @@ from core.mold_generator import MoldCavityGenerator
|
||||
from core.aluminum_foam_mold import AluminumFoamMoldGenerator
|
||||
from core.mold_quality_inspector import AluminumFoamMoldQualityInspector
|
||||
from core.mesh_generator import MeshGenerator
|
||||
from core.multi_scheme_planner import MultiSchemeMoldPlanner
|
||||
from services.storage_integration_rustfs import StorageIntegrationService
|
||||
from services.redis_task_manager import redis_task_manager
|
||||
from services.material_service import MaterialService
|
||||
@@ -39,6 +40,7 @@ class ProcessingService:
|
||||
self.mesh_generator = MeshGenerator(quality="medium")
|
||||
self.html_generator = HTMLGenerator()
|
||||
self.storage_service = StorageIntegrationService()
|
||||
self.multi_scheme_planner = MultiSchemeMoldPlanner()
|
||||
|
||||
# ─── 对外入口 ───
|
||||
|
||||
@@ -127,7 +129,7 @@ class ProcessingService:
|
||||
selected_material = MaterialService.get_material(requested_material)
|
||||
is_foam_material = MaterialService.is_foam_material(requested_material)
|
||||
|
||||
cavity_mesh_data = await self._step_generate_cavity(
|
||||
plan_result = await self._step_generate_cavity(
|
||||
shape, selected_material, is_foam_material
|
||||
)
|
||||
|
||||
@@ -136,19 +138,25 @@ class ProcessingService:
|
||||
db_session, task_id, "processing", 60, "生成型腔详细数据"
|
||||
)
|
||||
|
||||
detailed_cavity_json = CalculationService.build_detailed_cavity_json(
|
||||
detailed_cavity_json = CalculationService.build_plan_result(
|
||||
geometry_data=geometry_data,
|
||||
material=selected_material,
|
||||
file_path=str(file_path),
|
||||
cavity_mesh_data=cavity_mesh_data,
|
||||
plan_result=plan_result,
|
||||
)
|
||||
|
||||
if cavity_mesh_data and "mold_cavities" in cavity_mesh_data:
|
||||
mold_cavities = cavity_mesh_data["mold_cavities"]
|
||||
logger.info(f"型腔网格数据已合并: cavity {mold_cavities.get('cavity', {}).get('vertex_count', 0)} 顶点")
|
||||
best_scheme = CalculationService.get_best_scheme(detailed_cavity_json)
|
||||
best_cavity_data = best_scheme.get("cavity_data", {}) if best_scheme else {}
|
||||
best_key_info = best_scheme.get("key_info", {}) if best_scheme else {}
|
||||
|
||||
if best_cavity_data.get("mold_cavities"):
|
||||
cavity_geometry = best_cavity_data["mold_cavities"].get("cavity", {})
|
||||
logger.info(
|
||||
f"推荐方案型腔数据已合并: cavity {cavity_geometry.get('vertex_count', 0)} 顶点"
|
||||
)
|
||||
|
||||
# 5. 生成关键信息
|
||||
cavity_key_info = detailed_cavity_json["mold_cavities"]["cavity_key_info"]
|
||||
cavity_key_info = best_key_info
|
||||
|
||||
# 6. 保存几何数据到数据库
|
||||
await self.storage_service.update_task_status(
|
||||
@@ -162,12 +170,7 @@ class ProcessingService:
|
||||
geometry_data.get("analysis_method", "mold_cavity"),
|
||||
)
|
||||
|
||||
# 7. 保存模具型腔数据
|
||||
await self.storage_service.save_mold_cavity_data(
|
||||
db_session, stp_file_id, detailed_cavity_json
|
||||
)
|
||||
|
||||
# 8. 生成HTML可视化
|
||||
# 7. 生成HTML可视化
|
||||
await self.storage_service.update_task_status(
|
||||
db_session, task_id, "processing", 85, "生成可视化报告"
|
||||
)
|
||||
@@ -180,10 +183,26 @@ class ProcessingService:
|
||||
"point_count": mesh_result.get("point_count", 0),
|
||||
}
|
||||
|
||||
detailed_cavity_json = await self._attach_scheme_previews(
|
||||
detailed_cavity_json=detailed_cavity_json,
|
||||
geometry_data=geometry_data,
|
||||
stp_filename=Path(file_path).name,
|
||||
pointcloud_data=pointcloud_data,
|
||||
)
|
||||
|
||||
best_scheme = CalculationService.get_best_scheme(detailed_cavity_json)
|
||||
best_cavity_data = best_scheme.get("cavity_data", {}) if best_scheme else best_cavity_data
|
||||
best_key_info = best_scheme.get("key_info", {}) if best_scheme else best_key_info
|
||||
|
||||
# 8. 保存模具型腔数据(包含方案级预览链接)
|
||||
await self.storage_service.save_mold_cavity_data(
|
||||
db_session, stp_file_id, detailed_cavity_json
|
||||
)
|
||||
|
||||
html_file_path = self.html_generator.generate_and_save_visualization(
|
||||
geometry_data,
|
||||
Path(file_path).name,
|
||||
cavity_data=detailed_cavity_json,
|
||||
cavity_data=best_cavity_data,
|
||||
pointcloud_data=pointcloud_data,
|
||||
)
|
||||
|
||||
@@ -233,9 +252,12 @@ class ProcessingService:
|
||||
await redis_task_manager.update_task(task_id, {
|
||||
"geometry_data": geometry_data,
|
||||
"analysis_result": analysis_result,
|
||||
"cavity_data": detailed_cavity_json,
|
||||
"key_info": detailed_cavity_json,
|
||||
"html_file": f"/html/{Path(html_file_path).name}",
|
||||
"plan_result": detailed_cavity_json,
|
||||
"candidate_schemes": detailed_cavity_json.get("candidate_schemes", []),
|
||||
"best_scheme_id": detailed_cavity_json.get("best_scheme_id"),
|
||||
"cavity_data": best_cavity_data,
|
||||
"key_info": best_key_info,
|
||||
"html_file": best_scheme.get("html_file", f"/html/{Path(html_file_path).name}") if best_scheme else f"/html/{Path(html_file_path).name}",
|
||||
"verification": verification_result,
|
||||
"status": ProcessingStatus.COMPLETED,
|
||||
"completed_at": str(datetime.now()),
|
||||
@@ -327,28 +349,24 @@ class ProcessingService:
|
||||
async def _step_generate_cavity(
|
||||
self, shape, selected_material: dict, is_foam_material: bool,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""生成模具型腔数据"""
|
||||
cavity_mesh_data = None
|
||||
"""生成多方案分模结果"""
|
||||
plan_result = None
|
||||
try:
|
||||
if shape:
|
||||
if is_foam_material:
|
||||
self.aluminum_foam_generator.set_material(selected_material["name"])
|
||||
cavity_result = self.aluminum_foam_generator.generate_mold_cavities(shape)
|
||||
cavity_mesh_data = self.aluminum_foam_generator.generate_detailed_cavity_json(cavity_result)
|
||||
logger.info(f"使用铝泡沫模具生成器: {selected_material['name']}")
|
||||
else:
|
||||
cavity_result = self.mold_generator.generate_mold_cavities(shape)
|
||||
cavity_mesh_data = self.mold_generator.generate_detailed_cavity_json(cavity_result)
|
||||
logger.info(f"使用普通塑料模具生成器: {selected_material['name']}")
|
||||
|
||||
if cavity_mesh_data:
|
||||
logger.info(f"型腔网格数据生成完成: {cavity_mesh_data.get('mold_cavities', {}).get('cavity', {}).get('vertex_count', 0)} 顶点")
|
||||
plan_result = self.multi_scheme_planner.generate_plan(
|
||||
shape=shape,
|
||||
material=selected_material,
|
||||
is_foam_material=is_foam_material,
|
||||
)
|
||||
logger.info(
|
||||
f"多方案分模完成: 生成 {len(plan_result.get('candidate_schemes', []))} 套方案"
|
||||
)
|
||||
except Exception as cavity_err:
|
||||
logger.warning(f"型腔生成失败,使用简化数据: {cavity_err}")
|
||||
logger.warning(f"多方案分模失败,使用简化数据: {cavity_err}")
|
||||
traceback.print_exc()
|
||||
cavity_mesh_data = None
|
||||
plan_result = None
|
||||
|
||||
return cavity_mesh_data
|
||||
return plan_result
|
||||
|
||||
async def _step_verify(
|
||||
self, file_path: str, db_session: AsyncSession,
|
||||
@@ -379,6 +397,38 @@ class ProcessingService:
|
||||
logger.warning(f"FreeCAD验证失败(不影响主流程): {ve}")
|
||||
return {"status": "error", "error": str(ve)}
|
||||
|
||||
async def _attach_scheme_previews(
|
||||
self,
|
||||
detailed_cavity_json: Dict[str, Any],
|
||||
geometry_data: Dict[str, Any],
|
||||
stp_filename: str,
|
||||
pointcloud_data: Optional[Dict[str, Any]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""为每个候选分模方案生成独立HTML预览链接。"""
|
||||
candidate_schemes = detailed_cavity_json.get("candidate_schemes", [])
|
||||
if not candidate_schemes:
|
||||
return detailed_cavity_json
|
||||
|
||||
for scheme in candidate_schemes:
|
||||
cavity_data = scheme.get("cavity_data")
|
||||
if not cavity_data:
|
||||
continue
|
||||
suffix = scheme.get("scheme_id")
|
||||
html_path = self.html_generator.generate_and_save_visualization(
|
||||
geometry_data,
|
||||
stp_filename,
|
||||
cavity_data=cavity_data,
|
||||
pointcloud_data=pointcloud_data,
|
||||
suffix=suffix,
|
||||
)
|
||||
scheme["html_file"] = f"/html/{Path(html_path).name}"
|
||||
|
||||
best_scheme = CalculationService.get_best_scheme(detailed_cavity_json)
|
||||
if best_scheme:
|
||||
detailed_cavity_json["html_file"] = best_scheme.get("html_file")
|
||||
|
||||
return detailed_cavity_json
|
||||
|
||||
# ─── 指标持久化 ───
|
||||
|
||||
async def _save_analysis_metrics(self, session: AsyncSession, stp_file_id: int, analysis_result: dict):
|
||||
|
||||
@@ -62,6 +62,7 @@ class TaskQueryService:
|
||||
cavity_json: Optional[Dict[str, Any]] = file_with_data.get("mold_cavity_data")
|
||||
features_json: List[Dict[str, Any]] = file_with_data.get("features", [])
|
||||
recommendations_json: List[Dict[str, Any]] = file_with_data.get("recommendations", [])
|
||||
cavity_view = TaskQueryService._extract_cavity_view(cavity_json)
|
||||
|
||||
# 组装网格摘要
|
||||
mesh_summary = await TaskQueryService._get_mesh_summary(db_session, stp_file.id)
|
||||
@@ -78,6 +79,8 @@ class TaskQueryService:
|
||||
pass
|
||||
if html_file_record and html_file_record.filename:
|
||||
html_file_url = f"/html/{html_file_record.filename}"
|
||||
if cavity_view.get("html_file"):
|
||||
html_file_url = cavity_view.get("html_file")
|
||||
|
||||
# 构造与内存任务兼容的任务视图
|
||||
task_view = {
|
||||
@@ -93,8 +96,11 @@ class TaskQueryService:
|
||||
if processing_task.completed_time
|
||||
else "",
|
||||
"geometry_data": geometry_json,
|
||||
"key_info": cavity_json,
|
||||
"cavity_data": cavity_json,
|
||||
"key_info": cavity_view.get("key_info"),
|
||||
"cavity_data": cavity_view.get("cavity_data"),
|
||||
"candidate_schemes": cavity_view.get("candidate_schemes", []),
|
||||
"best_scheme_id": cavity_view.get("best_scheme_id"),
|
||||
"plan_result": cavity_json,
|
||||
"mesh_summary": mesh_summary,
|
||||
"html_file": html_file_url,
|
||||
"analysis_result": {
|
||||
@@ -141,3 +147,39 @@ class TaskQueryService:
|
||||
"quality": mesh_record.quality,
|
||||
}
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _extract_cavity_view(cavity_json: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""兼容旧单方案与新多方案结果视图。"""
|
||||
if not cavity_json:
|
||||
return {
|
||||
"cavity_data": None,
|
||||
"key_info": None,
|
||||
"candidate_schemes": [],
|
||||
"best_scheme_id": None,
|
||||
}
|
||||
|
||||
candidate_schemes = cavity_json.get("candidate_schemes")
|
||||
if candidate_schemes:
|
||||
best_scheme_id = cavity_json.get("best_scheme_id")
|
||||
best_scheme = candidate_schemes[0]
|
||||
if best_scheme_id:
|
||||
for scheme in candidate_schemes:
|
||||
if scheme.get("scheme_id") == best_scheme_id:
|
||||
best_scheme = scheme
|
||||
break
|
||||
return {
|
||||
"cavity_data": best_scheme.get("cavity_data"),
|
||||
"key_info": best_scheme.get("key_info"),
|
||||
"candidate_schemes": candidate_schemes,
|
||||
"best_scheme_id": best_scheme_id or best_scheme.get("scheme_id"),
|
||||
"html_file": best_scheme.get("html_file"),
|
||||
}
|
||||
|
||||
return {
|
||||
"cavity_data": cavity_json,
|
||||
"key_info": cavity_json,
|
||||
"candidate_schemes": [],
|
||||
"best_scheme_id": None,
|
||||
"html_file": cavity_json.get("html_file"),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user