Spaces:
Sleeping
Sleeping
| """MCP tool definitions for CAD review.""" | |
| from __future__ import annotations | |
| import logging | |
| from pathlib import Path | |
| logger = logging.getLogger(__name__) | |
| def register_tools(mcp): | |
| """Register all MCP tools.""" | |
| def get_assembly_tree(job_id: str) -> str: | |
| """Get the assembly tree structure for a loaded STEP file. | |
| Args: | |
| job_id: The job ID from uploading a STEP file. | |
| """ | |
| from src.api.router import get_manager | |
| manager = get_manager() | |
| job = manager.get_job(job_id) | |
| if job is None: | |
| return f"Error: Job not found: {job_id}" | |
| if job.assembly_tree is None: | |
| return f"Error: Assembly tree not available yet (status: {job.status})" | |
| import json | |
| return json.dumps(job.assembly_tree.to_dict(), indent=2) | |
| def get_part_info(job_id: str, part_id: str) -> str: | |
| """Get detailed information about a specific part. | |
| Args: | |
| job_id: The job ID. | |
| part_id: The part ID from the assembly tree. | |
| """ | |
| from src.api.router import get_manager | |
| manager = get_manager() | |
| job = manager.get_job(job_id) | |
| if job is None: | |
| return f"Error: Job not found: {job_id}" | |
| if job.assembly_tree is None: | |
| return "Error: Assembly tree not available yet" | |
| node = job.assembly_tree.find_by_id(part_id) | |
| if node is None: | |
| return f"Error: Part not found: {part_id}" | |
| import json | |
| info = node.to_dict() | |
| mesh = job.part_meshes.get(part_id) | |
| if mesh: | |
| info["mesh_vertices"] = len(mesh.vertices) | |
| info["mesh_triangles"] = len(mesh.triangles) | |
| return json.dumps(info, indent=2) | |
| def measure_part_distance(job_id: str, part_a_id: str, part_b_id: str) -> str: | |
| """Measure the minimum distance between two parts. | |
| Args: | |
| job_id: The job ID. | |
| part_a_id: ID of the first part. | |
| part_b_id: ID of the second part. | |
| """ | |
| from src.api.router import get_manager | |
| from src.geometry.measurement import measure_distance | |
| manager = get_manager() | |
| job = manager.get_job(job_id) | |
| if job is None: | |
| return f"Error: Job not found: {job_id}" | |
| if job.assembly_tree is None: | |
| return "Error: Assembly tree not available yet" | |
| node_a = job.assembly_tree.find_by_id(part_a_id) | |
| node_b = job.assembly_tree.find_by_id(part_b_id) | |
| if node_a is None or node_a.shape is None: | |
| return f"Error: Part not found or has no shape: {part_a_id}" | |
| if node_b is None or node_b.shape is None: | |
| return f"Error: Part not found or has no shape: {part_b_id}" | |
| result = measure_distance(node_a.shape, node_b.shape) | |
| import json | |
| return json.dumps({ | |
| "distance_mm": result.distance_mm, | |
| "point_a": result.point_a, | |
| "point_b": result.point_b, | |
| }, indent=2) | |
| def check_compliance_rules(job_id: str) -> str: | |
| """Run compliance checks on the loaded assembly. | |
| Args: | |
| job_id: The job ID. | |
| """ | |
| from src.api.router import get_manager | |
| from src.compliance.kmvss_checker import check_compliance | |
| from src.compliance.rule_loader import load_rules | |
| manager = get_manager() | |
| job = manager.get_job(job_id) | |
| if job is None: | |
| return f"Error: Job not found: {job_id}" | |
| if job.assembly_tree is None: | |
| return "Error: Assembly tree not available yet" | |
| rules_path = Path(__file__).parent.parent.parent / "config" / "kmvss_rules.yaml" | |
| rules = load_rules(rules_path) | |
| results = check_compliance(rules, job.assembly_tree) | |
| import json | |
| return json.dumps([{ | |
| "rule": r.rule_name, | |
| "passed": r.passed, | |
| "message": r.message, | |
| "severity": r.severity, | |
| } for r in results], indent=2) | |
| def get_collision_report(job_id: str) -> str: | |
| """Get a collision/proximity report for all parts. | |
| Args: | |
| job_id: The job ID. | |
| """ | |
| from src.api.router import get_manager | |
| from src.geometry.measurement import scan_proximity | |
| manager = get_manager() | |
| job = manager.get_job(job_id) | |
| if job is None: | |
| return f"Error: Job not found: {job_id}" | |
| if job.assembly_tree is None: | |
| return "Error: Assembly tree not available yet" | |
| parts = [] | |
| for leaf in job.assembly_tree.iter_leaves(): | |
| if leaf.shape is not None and not leaf.shape.IsNull(): | |
| parts.append({"id": leaf.id, "name": leaf.name, "shape": leaf.shape}) | |
| results = scan_proximity(parts) | |
| import json | |
| return json.dumps([{ | |
| "part_a": r.part_a_name, | |
| "part_b": r.part_b_name, | |
| "distance_mm": r.min_distance_mm, | |
| "status": r.status, | |
| } for r in results], indent=2) | |