优化skill,添加特征树、编辑窗口
This commit is contained in:
@@ -16,6 +16,78 @@
|
||||
"simplecadapi_brep_compare"
|
||||
]
|
||||
},
|
||||
"routing_catalog": {
|
||||
"selection_rule": "For a new model, choose SimpleCADAPI only when the requested primary object matches one catalog entry. Feature-context matches are excluded. Every other request chooses build123d.",
|
||||
"source": "SimpleCADAPI/src/simplecadapi/std/{gear,bearing,chain,fastener}.py",
|
||||
"simplecadapi_standard_part_types": [
|
||||
{
|
||||
"type": "spur_gear",
|
||||
"factory": "simplecadapi.std.gear.make_spur_gear_rsolid",
|
||||
"aliases": ["齿轮", "直齿轮", "正齿轮", "spur gear"],
|
||||
"feature_context_exclusions": ["齿轮孔", "齿轮安装", "齿轮座", "齿轮箱", "gear hole", "gear mount", "gear housing", "gearbox"]
|
||||
},
|
||||
{
|
||||
"type": "straight_bevel_gear",
|
||||
"factory": "simplecadapi.std.gear.make_straight_bevel_gear_rsolid",
|
||||
"aliases": ["直齿锥齿轮", "锥齿轮", "straight bevel gear", "bevel gear"],
|
||||
"feature_context_exclusions": ["锥齿轮箱", "bevel gearbox", "锥齿轮座"]
|
||||
},
|
||||
{
|
||||
"type": "helical_gear",
|
||||
"factory": "simplecadapi.std.gear.make_helical_gear_rsolid",
|
||||
"aliases": ["斜齿轮", "helical gear"],
|
||||
"feature_context_exclusions": ["斜齿轮箱", "helical gearbox", "斜齿轮座"]
|
||||
},
|
||||
{
|
||||
"type": "herringbone_gear",
|
||||
"factory": "simplecadapi.std.gear.make_herringbone_gear_rsolid",
|
||||
"aliases": ["人字齿轮", "herringbone gear"],
|
||||
"feature_context_exclusions": ["人字齿轮箱", "herringbone gearbox", "人字齿轮座"]
|
||||
},
|
||||
{
|
||||
"type": "ring_gear",
|
||||
"factory": "simplecadapi.std.gear.make_spur_ring_gear_rsolid",
|
||||
"aliases": ["内齿圈", "齿圈", "ring gear"],
|
||||
"feature_context_exclusions": ["齿圈座", "ring gear housing", "ring gear mount"]
|
||||
},
|
||||
{
|
||||
"type": "gear_rack",
|
||||
"factory": "simplecadapi.std.gear.make_spur_rack_rsolid",
|
||||
"aliases": ["齿条", "直齿条", "斜齿条", "人字齿条", "gear rack", "rack gear", "spur rack", "helical rack", "herringbone rack"],
|
||||
"feature_context_exclusions": ["齿条安装", "齿条座", "rack mount", "rack housing"]
|
||||
},
|
||||
{
|
||||
"type": "cycloidal_disc",
|
||||
"factory": "simplecadapi.std.gear.make_cycloidal_disc_rsolid",
|
||||
"aliases": ["摆线盘", "摆线轮", "cycloidal disc"],
|
||||
"feature_context_exclusions": ["摆线减速器", "cycloidal reducer", "摆线针轮减速器"]
|
||||
},
|
||||
{
|
||||
"type": "ball_bearing",
|
||||
"factory": "simplecadapi.std.bearing.make_ball_bearing_rassembly",
|
||||
"aliases": ["轴承", "滚动轴承", "球轴承", "深沟球轴承", "ball bearing"],
|
||||
"feature_context_exclusions": ["轴承座", "轴承壳", "轴承孔", "轴承安装", "bearing housing", "bearing seat", "bearing hole", "bearing mount"]
|
||||
},
|
||||
{
|
||||
"type": "roller_chain_sprocket",
|
||||
"factory": "simplecadapi.std.chain.make_roller_chain_sprocket_rsolid",
|
||||
"aliases": ["滚子链轮", "链轮", "roller chain sprocket", "sprocket"],
|
||||
"feature_context_exclusions": ["链轮座", "链轮箱", "链轮安装", "sprocket housing", "sprocket mount"]
|
||||
},
|
||||
{
|
||||
"type": "bolt",
|
||||
"factory": "simplecadapi.std.fastener.make_bolt_rsolid",
|
||||
"aliases": ["螺栓", "六角螺栓", "内六角螺栓", "螺栓本体", "bolt", "hex bolt", "socket head bolt"],
|
||||
"feature_context_exclusions": ["螺栓孔", "螺栓圆", "螺栓阵列", "bolt hole", "bolt circle", "bolt pattern"]
|
||||
},
|
||||
{
|
||||
"type": "nut",
|
||||
"factory": "simplecadapi.std.fastener.make_nut_rsolid",
|
||||
"aliases": ["螺母", "六角螺母", "螺母本体", "nut", "hex nut"],
|
||||
"feature_context_exclusions": ["螺母槽", "螺母孔", "螺母避让", "nut pocket", "nut hole", "nut clearance"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"backends": {
|
||||
"build123d": {
|
||||
"project": "text-to-cad",
|
||||
|
||||
@@ -181,6 +181,49 @@ def contains_any(text: str, terms: tuple[str, ...]) -> bool:
|
||||
return any(term in text for term in terms)
|
||||
|
||||
|
||||
def simplecadapi_standard_part_match(
|
||||
request: str,
|
||||
registry: dict[str, object],
|
||||
) -> dict[str, object] | None:
|
||||
"""Match only a requested *primary* standard part, never a feature word.
|
||||
|
||||
The catalog is maintained beside the router from the actual SimpleCADAPI
|
||||
``simplecadapi.std`` factories. This is intentionally deterministic: an
|
||||
unmatched or ambiguous request is a build123d request.
|
||||
"""
|
||||
catalog = registry.get("routing_catalog", {})
|
||||
rules = (
|
||||
catalog.get("simplecadapi_standard_part_types", [])
|
||||
if isinstance(catalog, dict)
|
||||
else []
|
||||
)
|
||||
text = request.casefold()
|
||||
best_match: tuple[int, dict[str, object], list[str]] | None = None
|
||||
for raw_rule in rules:
|
||||
if not isinstance(raw_rule, dict):
|
||||
continue
|
||||
aliases = [str(value).casefold() for value in raw_rule.get("aliases", [])]
|
||||
exclusions = [str(value).casefold() for value in raw_rule.get("feature_context_exclusions", [])]
|
||||
matched_aliases = [alias for alias in aliases if alias and alias in text]
|
||||
if not matched_aliases:
|
||||
continue
|
||||
if any(exclusion and exclusion in text for exclusion in exclusions):
|
||||
continue
|
||||
# Generic terms such as "gear" must never hide a more specific
|
||||
# standard-part type such as "herringbone gear".
|
||||
specificity = max(len(alias) for alias in matched_aliases)
|
||||
if best_match is None or specificity > best_match[0]:
|
||||
best_match = (specificity, raw_rule, matched_aliases)
|
||||
if best_match is None:
|
||||
return None
|
||||
_, rule, matched_aliases = best_match
|
||||
return {
|
||||
"type": rule.get("type"),
|
||||
"factory": rule.get("factory"),
|
||||
"matched_aliases": matched_aliases,
|
||||
}
|
||||
|
||||
|
||||
def infer_experience_query(request: str) -> tuple[str | None, list[str]]:
|
||||
text = request.lower()
|
||||
family = next(
|
||||
@@ -559,6 +602,127 @@ def route(args: argparse.Namespace) -> dict[str, object]:
|
||||
assembly=args.assembly,
|
||||
source_backend=source_backend,
|
||||
)
|
||||
if not edit_context and args.backend == "auto":
|
||||
registry = json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
|
||||
standard_part = simplecadapi_standard_part_match(request, registry)
|
||||
if not standard_part:
|
||||
requirements = [
|
||||
requirement
|
||||
for requirement in requirements
|
||||
if requirement != "standard_mechanical_factory"
|
||||
]
|
||||
agent_experiences = (
|
||||
experience_context.get("experiences", [])
|
||||
if isinstance(experience_context, dict)
|
||||
else []
|
||||
)
|
||||
agent_generalized_methods = [
|
||||
{
|
||||
key: item[key]
|
||||
for key in (
|
||||
"id",
|
||||
"kind",
|
||||
"guidance",
|
||||
"check",
|
||||
"repair",
|
||||
"confidence",
|
||||
"reconstruction_grammar",
|
||||
)
|
||||
if isinstance(item, dict) and key in item
|
||||
}
|
||||
for item in agent_experiences
|
||||
if isinstance(item, dict)
|
||||
]
|
||||
agent_reconstruction_grammars = [
|
||||
item["reconstruction_grammar"]
|
||||
for item in agent_experiences
|
||||
if isinstance(item, dict)
|
||||
and item.get("kind") == "reconstruction_grammar"
|
||||
and "reconstruction_grammar" in item
|
||||
]
|
||||
selected_name = "simplecadapi" if standard_part else "build123d"
|
||||
backend_info = registry["backends"][selected_name]
|
||||
source_of_truth = (
|
||||
"simplecadapi model graph with native Python source"
|
||||
if selected_name == "simplecadapi"
|
||||
else "build123d native Python source"
|
||||
)
|
||||
selection_reason = (
|
||||
"matched SimpleCADAPI standard-part catalog entry "
|
||||
f"{standard_part['type']} ({standard_part['factory']})"
|
||||
if standard_part
|
||||
else "no SimpleCADAPI standard-part catalog entry matched; use the general text-to-cad/build123d backend"
|
||||
)
|
||||
return {
|
||||
"schema_version": "1.0",
|
||||
"request": request,
|
||||
"selected_backend": selected_name,
|
||||
"runner_skill": backend_info["runner_skill"],
|
||||
"project": backend_info["project"],
|
||||
"adapter": None,
|
||||
"confidence": "high",
|
||||
"routing_policy": {
|
||||
"version": "4.0",
|
||||
"selection_scope": "new_model_primary_part_type",
|
||||
"requirements": requirements,
|
||||
"decision_authority": "cad_router_standard_part_catalog",
|
||||
"keyword_backend_scoring": True,
|
||||
"fallback_policy": "unmatched_requests_use_build123d",
|
||||
"standard_part_match": standard_part,
|
||||
"server_side_template_generation": False,
|
||||
"effective_execution_engine": selected_name,
|
||||
"validation_engines": ["backend_geometry_validation"],
|
||||
},
|
||||
"backend_scores": [
|
||||
{
|
||||
"backend": selected_name,
|
||||
"score": 100,
|
||||
"reasons": [selection_reason],
|
||||
},
|
||||
{
|
||||
"backend": "build123d" if selected_name == "simplecadapi" else "simplecadapi",
|
||||
"score": 0,
|
||||
"reasons": ["not selected by the standard-part catalog"],
|
||||
},
|
||||
],
|
||||
"fallback_order": ["build123d"] if selected_name == "simplecadapi" else [],
|
||||
"workflow_profiles": [],
|
||||
"artifact_contract": {
|
||||
"primary_format": "step",
|
||||
"editable_contract": "DesignIR 3.0 normalized contract",
|
||||
"editable_contract_role": "contract_after_backend_generation",
|
||||
"authoritative_geometry_source": source_of_truth,
|
||||
},
|
||||
"source_of_truth": source_of_truth,
|
||||
"experience_context": experience_context,
|
||||
"design_plan": {
|
||||
"plan_kind": "deterministic_standard_part_route",
|
||||
"operation": "create",
|
||||
"part_family": experience_family or "unclassified",
|
||||
"requested_feature_roles": sorted(set(experience_features)),
|
||||
"selected_backend": selected_name,
|
||||
"source_of_truth": source_of_truth,
|
||||
"standard_part_match": standard_part,
|
||||
"generalized_methods": agent_generalized_methods,
|
||||
"reconstruction_grammars": agent_reconstruction_grammars,
|
||||
"experience_status": (
|
||||
"matched"
|
||||
if experience_context and experience_context.get("experiences")
|
||||
else "no_promoted_method_matched"
|
||||
),
|
||||
"execution_steps": [
|
||||
"CAD Router selects the backend from the standard-part catalog.",
|
||||
"Agent writes backend-native Python source for the full request.",
|
||||
"Server executes the submitted source and rejects missing artifacts.",
|
||||
"Server normalizes backend output into DesignIR 3.0.",
|
||||
],
|
||||
},
|
||||
"project_contributions": {
|
||||
"text-to-cad": "default backend for every request outside the SimpleCADAPI standard-part catalog",
|
||||
"SimpleCADAPI": "backend for the catalogued standard mechanical part types only",
|
||||
},
|
||||
"availability": None,
|
||||
}
|
||||
scores = {
|
||||
"build123d": BackendScore(
|
||||
"build123d",
|
||||
@@ -692,12 +856,13 @@ def route(args: argparse.Namespace) -> dict[str, object]:
|
||||
|
||||
registry = json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
|
||||
backend_info = registry["backends"][selected.name]
|
||||
editable_contract = "DesignIR 3.0"
|
||||
source_of_truth = (
|
||||
"per-part DesignIR 3.0 with an isolated SurfaceIR compiler"
|
||||
if teacher_step_reconstruction
|
||||
else "per-part semantic DesignIR 3.0 with an isolated backend compiler"
|
||||
)
|
||||
editable_contract = "DesignIR 3.0 normalized contract"
|
||||
if teacher_step_reconstruction:
|
||||
source_of_truth = "surfaceir_designir"
|
||||
elif selected.name == "simplecadapi":
|
||||
source_of_truth = "simplecadapi model graph with native Python source"
|
||||
else:
|
||||
source_of_truth = "build123d native Python source"
|
||||
gap = selected.score - max((scores[name].score for name in scores if name != selected.name), default=0)
|
||||
confidence = "high" if gap >= 40 else "medium" if gap >= 15 else "low"
|
||||
result: dict[str, object] = {
|
||||
@@ -740,6 +905,8 @@ def route(args: argparse.Namespace) -> dict[str, object]:
|
||||
"artifact_contract": {
|
||||
"primary_format": "step",
|
||||
"editable_contract": editable_contract,
|
||||
"editable_contract_role": "contract_after_backend_generation",
|
||||
"authoritative_geometry_source": source_of_truth,
|
||||
},
|
||||
"source_of_truth": source_of_truth,
|
||||
"experience_context": experience_context,
|
||||
@@ -831,10 +998,10 @@ def route(args: argparse.Namespace) -> dict[str, object]:
|
||||
if edit_context
|
||||
else [
|
||||
"Resolve explicit user dimensions and preserve them as authoritative parameters.",
|
||||
"Instantiate matched reconstruction grammars as DesignIR parameters, datums, constraints, and canonical feature stages; never copy teacher geometry.",
|
||||
"Translate requested feature roles and matched generalized methods into backend operations.",
|
||||
"Generate the editable source of truth and STEP artifact.",
|
||||
"Validate topology, dimensions, feature relationships, surface mix, and export integrity against the grammar validation roles.",
|
||||
"Translate requested feature roles and matched generalized methods into the selected backend's native operations.",
|
||||
"Generate backend-native source or model graph and export the primary STEP artifact.",
|
||||
"Normalize backend metadata into DesignIR 3.0 for parameters, feature tree, validation, and future edit bindings.",
|
||||
"Validate topology, dimensions, feature relationships, surface mix, and export integrity against the brief.",
|
||||
]
|
||||
),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user