Files
OnebotCatalog/onebot-data/tools/infer-sku-template.py
wangruiguo fc5ee1dd36 v2.1: DESTACO 风格选型界面 + 参数组合补全(缺组合也能出零件号)
网页版选型改版 (仅网页版, 桌面版待同步)
- 新增零件号实时条: 边选边拼, 已确定片段实心高亮, 未定片段虚化, 进度条随选推进;
  浅色配色 (初版深色块与页面不协调, 已改); 选满且唯一命中时整块转青色实心
- 技术方案: 40 系列中仅 KC 有编码模板 → 改用「当前候选型号的最长公共前缀」,
  已验证 40/40 系列前缀单调增长(不回退)
- 参数选择由下拉菜单改为可视化选项块: 悬停抬升+青色投影, 选中青色填充+✓,
  不可选取值置灰(虚线+划线, 不消失, 让用户看到选项存在但当前组合不适用),
  再点一次取消; 有说明的显示代号+说明, 纯数值用紧凑文字块
- 参数联动仍复用 allowedOptions 规则引擎, 语义未变, 只改渲染

参数组合补全
- 原逻辑: 必须有真实数模才能生成型号 → 库里没有的组合选不出来也出不了号
- infer-sku-template.py 从已有型号反推编码模板, 得 23 个系列 100% 可复现
- verify-templates.py 作为门禁: 用模板重渲染每个已有型号必须逐字一致 ——
  该检查抓出 ULM/ULP 行程补零位数写错(2位写3位), 否则会生成 3000 个不存在的零件号
- gen-missing-combos.py 补全 8 个系列共 3157 个型号 (全库 54136 → 57293)
- 占位数模: 3157 个型号共用 1 个 PLACEHOLDER.step(4.5KB), 构建器按路径打包只存一份,
  数据包仅 2.10GB → 2.14GB (中途用硬链接方案踩坑: NTFS 上限 1024, 超出退化为拷贝白占 500MB)
- _pending_models.csv 输出待补数模清单, 供 AI 补完后替换 step_file

新增脚本: infer-sku-template / verify-templates / quantify-combo-gap /
          gen-missing-combos / gen-placeholder-step / check-combo-unique
新增文档: docs/更改说明-v2.1.md

发现未处理 (已记录在更改说明):
- 夹紧缸 9 系列一组参数对应多型号 (310 个型号, 编码含参数外尾缀, 旧码/新码混用)
- UAGP/LAGP 参数顺序与官方编码结构不符 (传感器应在转角之前)
- 17 个系列因模板不干净未补全 (宁可少补, 不生成可能不存在的零件号)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-15 02:14:55 +08:00

110 lines
3.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
编码模板反推 v2 —— 支持零填充与空值占位符。
v1 的 explain() 贪心匹配"非零填充", 把 ULP50040AEK0 的 "040" 拆成 字面量"0" + 值"40",
产生大量假阴性。真实规则是:
- 数值参数常带前导零 (stroke=40 -> "040")
- 枚举参数为空时, 编码里用 '_' 占位 (UAGP075_K045WS0)
本脚本对每个参数尝试 {原值, 各前导零位数, '_'占位} 的所有组合, 取能对齐的;
若某系列的"字面量序列"完全一致 → 可模板化。
用法: PYTHONUTF8=1 python infer-sku-template.py
"""
import json, io, collections, sys
CAT = r'D:/开发/OnebotCatalog/release/web_2026.08/catalog.json'
d = json.load(io.open(CAT, encoding='utf-8-sig'))
MAXPAD = 4
def align_all(code, params, values):
"""返回全部可能的字面量序列 (元组)。每个参数尝试: 原值 / 前导零 / '_'占位。"""
results = []
def dfs(i, pos, lits):
if i == len(params):
results.append(tuple(lits + [code[pos:]]))
return
pc = params[i]
v = str(values.get(pc, ''))
cands = []
if v == '':
cands = ['_', ''] # 空值: 占位符或什么都不写
else:
cands = [v] + ['0' * z + v for z in range(1, MAXPAD + 1)]
seen = set()
for pat in cands:
if pat in seen:
continue
seen.add(pat)
if pat == '':
dfs(i + 1, pos, lits + [''])
continue
idx = code.find(pat, pos)
if idx >= 0:
dfs(i + 1, idx + len(pat), lits + [code[pos:idx]])
dfs(0, 0, [])
return results
def render_template(params, lits):
"""字面量序列 -> 模板串。空值参数渲染为 '_'。"""
out = ''
for i, pc in enumerate(params):
out += lits[i] + '{' + pc + '}'
out += lits[len(params)]
return out
good, bad = [], []
for s in d['series']:
vs = s.get('variants') or []
if not vs:
continue
params = [p['code'] for p in s['parameters']]
lit_sets = []
unaligned = 0
for v in vs:
alts = align_all(v['modelCode'], params, v['params'])
if not alts:
unaligned += 1
continue
lit_sets.append(alts)
if not lit_sets:
bad.append((s['code'], len(vs), '完全无法对齐', [], 0))
continue
# 统计"出现在最多变体里"的字面量序列 (每个变体取任一可对齐解)
cnt = collections.Counter()
for alts in lit_sets:
for a in set(alts):
cnt[a] += 1
top, hit = cnt.most_common(1)[0]
rate = hit / len(vs) * 100
if rate >= 99.5 and unaligned == 0:
good.append((s['code'], len(vs), rate, render_template(params, top), len(cnt)))
else:
bad.append((s['code'], len(vs), f'{rate:.1f}% ({len(cnt)} 种)', cnt.most_common(3), unaligned))
print('=' * 96)
print(f'可模板化的系列 ({len(good)} 个)')
print('=' * 96)
for code, n, rate, tpl, k in sorted(good):
print(f'{code:7s} {n:6d} 变体 {rate:6.1f}% {tpl}')
print()
print('=' * 96)
print(f'不可模板化的系列 ({len(bad)} 个)')
print('=' * 96)
for code, n, why, tops, un in sorted(bad, key=lambda x: -x[1]):
print(f'{code:7s} {n:6d} 变体 {why}' + (f' 未对齐 {un}' if un else ''))
for lits, c in tops[:3]:
print(f' {c:5d}× {lits}')
print(f'\n合计: 可模板化 {len(good)} / 共 {len(good) + len(bad)} 个系列')