Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import re | |
| from typing import Any | |
| from .models import Design | |
| def clamp(value: float, low: float, high: float) -> float: | |
| return max(low, min(high, value)) | |
| def infer_load_case(prompt: str, design: Design) -> dict[str, Any]: | |
| """Resolve natural-language load details to simulation boundary data. | |
| The LLM can propose load location through the design fields. This manager | |
| resolves that proposal into a concrete point/region and records assumptions. | |
| If the prompt explicitly says torque, cyclic, impact, chair, motor, or fixture, | |
| those details alter the load case. | |
| """ | |
| text = (prompt or "").lower() | |
| load_x = clamp(abs(design.load_point_x_mm), 5, design.base_length_mm) | |
| load_y = clamp(design.load_point_y_mm, -design.base_width_mm / 2, design.base_width_mm / 2) | |
| nearest_boss = min( | |
| [feature for feature in design.features if feature.type == "boss"], | |
| key=lambda feature: (feature.x - load_x) ** 2 + (feature.y - load_y) ** 2, | |
| default=None, | |
| ) | |
| load_z = design.base_thickness_mm | |
| load_region_hint = "tip_boss" | |
| if nearest_boss is not None: | |
| load_x = nearest_boss.x | |
| load_y = nearest_boss.y | |
| load_z = design.base_thickness_mm + max(nearest_boss.height, 1) | |
| load_region_hint = "top_of_nearest_load_boss" | |
| factor = 3.0 if "impact" in text else 1.5 if ("cyclic" in text or "fatigue" in text) else 1.0 | |
| torque_match = re.search(r"(\d+(?:\.\d+)?)\s*(?:n\s*[-*]?\s*m|nm|newton\s*meter)", text) | |
| if torque_match: | |
| torque_nm = float(torque_match.group(1)) | |
| equivalent_force = torque_nm * 1000 / max(load_x, 1) | |
| return { | |
| "type": "torque_as_force_couple_proxy", | |
| "effective_load_n": equivalent_force * factor, | |
| "nominal_load_n": equivalent_force, | |
| "factor": factor, | |
| "load_point": [load_x, load_y, load_z], | |
| "vector_n": [0, 0, -round(equivalent_force * factor, 4)], | |
| "fixed_region": "left_face", | |
| "load_region": "shaft_proxy_or_" + load_region_hint, | |
| "note": f"{torque_nm} Nm converted to equivalent force at {load_x:.1f} mm lever arm.", | |
| } | |
| if "chair" in text or "seat" in text: | |
| load_type = "distributed_downward_proxy" | |
| load_region = "seat_surface_proxy" | |
| elif "motor" in text: | |
| load_type = "motor_mount_tip_or_boss_load" | |
| load_region = "motor_boss_or_tip" | |
| else: | |
| load_type = "cantilever_tip_load" | |
| load_region = load_region_hint | |
| return { | |
| "type": load_type, | |
| "effective_load_n": abs(design.load_newtons) * factor, | |
| "nominal_load_n": abs(design.load_newtons), | |
| "factor": factor, | |
| "load_point": [load_x, load_y, load_z], | |
| "vector_n": [0, 0, -round(abs(design.load_newtons) * factor, 4)], | |
| "fixed_region": "left_face", | |
| "load_region": load_region, | |
| "note": "Defaulted to fixed left face and downward load at the model-proposed tip/load point.", | |
| } | |