Prefer CN device matches

This commit is contained in:
2026-04-24 10:15:55 +08:00
parent c9a2d13945
commit d36669103e
7 changed files with 42441 additions and 44883 deletions
+9549 -11680
View File
File diff suppressed because it is too large Load Diff
+32835 -33191
View File
File diff suppressed because it is too large Load Diff
+25 -1
View File
@@ -299,6 +299,22 @@ def normalize_alias_list(*groups: object) -> List[str]:
return aliases return aliases
def is_preferred_cn_source_file(source_file: str) -> bool:
source = str(source_file or "").strip().lower()
if not source:
return False
if source == MANUAL_SOURCE_FILE:
return True
return not (source.endswith("_en.md") or source.endswith("_global_en.md"))
def first_preferred_match(records: List[DeviceRecord]) -> List[DeviceRecord]:
if not records:
return []
cn_records = [record for record in records if is_preferred_cn_source_file(record.source_file)]
return [(cn_records or records)[0]]
def load_manual_catalog(repo_root: Path) -> dict[str, object]: def load_manual_catalog(repo_root: Path) -> dict[str, object]:
path = repo_root / MANUAL_SOURCE_FILE path = repo_root / MANUAL_SOURCE_FILE
if not path.exists(): if not path.exists():
@@ -719,7 +735,15 @@ class DeviceMapper:
} }
matched_records = [r for r in [self.records_by_id[rid] for rid in candidate_ids] if self._brand_match(fallback_filter, r)] matched_records = [r for r in [self.records_by_id[rid] for rid in candidate_ids] if self._brand_match(fallback_filter, r)]
matched_records.sort(key=lambda r: (r.device_name, r.source_file, r.id)) matched_records.sort(
key=lambda r: (
0 if is_preferred_cn_source_file(r.source_file) else 1,
r.device_name,
r.source_file,
r.id,
)
)
matched_records = first_preferred_match(matched_records)
if matched_records: if matched_records:
best = matched_records[0] best = matched_records[0]
+18 -6
View File
@@ -857,6 +857,18 @@ def run_mysql_query(sql: str, database: str | None = None) -> list[dict[str, str
return rows return rows
SQL_CN_SOURCE_ORDER = """
CASE
WHEN source_file = 'local/manual_catalog.json'
OR (source_file NOT LIKE '%_en.md' AND source_file NOT LIKE '%_global_en.md')
THEN 0
ELSE 1
END ASC,
source_rank ASC,
record_id ASC
""".strip()
def build_sql_query_payload(payload: dict[str, object]) -> dict[str, object]: def build_sql_query_payload(payload: dict[str, object]) -> dict[str, object]:
raw_value = str(payload.get("model_raw") or payload.get("model") or "").strip() raw_value = str(payload.get("model_raw") or payload.get("model") or "").strip()
if not raw_value: if not raw_value:
@@ -871,7 +883,7 @@ def build_sql_query_payload(payload: dict[str, object]) -> dict[str, object]:
limit = int(limit_value) limit = int(limit_value)
except Exception as err: except Exception as err:
raise RuntimeError("limit 必须是数字。") from err raise RuntimeError("limit 必须是数字。") from err
limit = max(1, min(limit, 100)) limit = 1
exact_sql = f""" exact_sql = f"""
SELECT SELECT
@@ -893,7 +905,7 @@ SELECT
ver_name ver_name
FROM mobilemodels.mm_device_catalog FROM mobilemodels.mm_device_catalog
WHERE alias_norm = '{sql_string(alias_norm)}' WHERE alias_norm = '{sql_string(alias_norm)}'
ORDER BY source_rank ASC, record_id ASC ORDER BY {SQL_CN_SOURCE_ORDER}
LIMIT {limit}; LIMIT {limit};
""".strip() """.strip()
@@ -929,7 +941,7 @@ SELECT
ver_name ver_name
FROM mobilemodels.mm_device_catalog FROM mobilemodels.mm_device_catalog
WHERE {name_conditions} WHERE {name_conditions}
ORDER BY source_rank ASC, record_id ASC ORDER BY {SQL_CN_SOURCE_ORDER}
LIMIT {limit}; LIMIT {limit};
""".strip() """.strip()
rows = run_mysql_query(sql) rows = run_mysql_query(sql)
@@ -961,7 +973,7 @@ def build_sql_device_name_query_payload(payload: dict[str, object]) -> dict[str,
limit = int(limit_value) limit = int(limit_value)
except Exception as err: except Exception as err:
raise RuntimeError("limit 必须是数字。") from err raise RuntimeError("limit 必须是数字。") from err
limit = max(1, min(limit, 100)) limit = 1
alias_norm = normalize_text(raw_value) alias_norm = normalize_text(raw_value)
resolved_device_names = resolve_index_device_names(alias_norm) if alias_norm else [] resolved_device_names = resolve_index_device_names(alias_norm) if alias_norm else []
@@ -994,7 +1006,7 @@ SELECT
ver_name ver_name
FROM mobilemodels.mm_device_catalog FROM mobilemodels.mm_device_catalog
WHERE {name_conditions} WHERE {name_conditions}
ORDER BY source_rank ASC, record_id ASC ORDER BY {SQL_CN_SOURCE_ORDER}
LIMIT {limit}; LIMIT {limit};
""".strip() """.strip()
rows = run_mysql_query(sql) rows = run_mysql_query(sql)
@@ -1026,7 +1038,7 @@ SELECT
FROM mobilemodels.mm_device_catalog FROM mobilemodels.mm_device_catalog
WHERE device_name LIKE '%{sql_string(raw_value)}%' WHERE device_name LIKE '%{sql_string(raw_value)}%'
OR ver_name LIKE '%{sql_string(raw_value)}%' OR ver_name LIKE '%{sql_string(raw_value)}%'
ORDER BY source_rank ASC, record_id ASC ORDER BY {SQL_CN_SOURCE_ORDER}
LIMIT {limit}; LIMIT {limit};
""".strip() """.strip()
rows = run_mysql_query(sql) rows = run_mysql_query(sql)
+7 -2
View File
@@ -1688,7 +1688,10 @@ NOH-AL00 -> nohal00</pre>
} }
function isCnSourceFile(sourceFile) { function isCnSourceFile(sourceFile) {
return /_cn\.md$/i.test(sourceFile || ""); const source = String(sourceFile || "").trim().toLowerCase();
if (!source) return false;
if (source === "local/manual_catalog.json") return true;
return !(/_en\.md$/i.test(source) || /_global_en\.md$/i.test(source));
} }
function buildInitialSourceOrder() { function buildInitialSourceOrder() {
@@ -2045,7 +2048,9 @@ NOH-AL00 -> nohal00</pre>
const topBase = brandStrictMatches.length const topBase = brandStrictMatches.length
? brandStrictMatches ? brandStrictMatches
: (manufacturerStrictMatches.length ? manufacturerStrictMatches : allMatches); : (manufacturerStrictMatches.length ? manufacturerStrictMatches : allMatches);
const top = topBase.slice(0, 200); const preferredTopBase = topBase.filter((x) => isCnSourceFile(x.record && x.record.source_file));
const topSourceBase = preferredTopBase.length ? preferredTopBase : topBase;
const top = topSourceBase.slice(0, 1);
const best = top.length ? top[0] : null; const best = top.length ? top[0] : null;
+4 -2
View File
@@ -280,10 +280,12 @@
`CPH2583`: 一加 12 北美版 `CPH2583`: 一加 12 北美版
**一加 Ace 3 / 一加 12R (`aston`) / 一加 Ace 3 原神刻晴定制机 / 一加 12R Genshin Impact Edition (`martin`):** **一加 Ace 3 (`aston`):**
`PJE110`: 一加 Ace 3 国行版 / 原神刻晴定制机 `PJE110`: 一加 Ace 3 国行版 / 原神刻晴定制机
**一加 12R (`aston`):**
`CPH2585`: 一加 12R 印度版 / 原神刻晴定制机 `CPH2585`: 一加 12R 印度版 / 原神刻晴定制机
`CPH2609`: 一加 12R 欧洲版 / 国际版 / 原神刻晴定制机 `CPH2609`: 一加 12R 欧洲版 / 国际版 / 原神刻晴定制机
@@ -574,4 +576,4 @@
`OPWWE251`: 一加手表 3 国际版 `OPWWE251`: 一加手表 3 国际版
`OPWE242`: 一加手表 3 43mm 国际版 `OPWE242`: 一加手表 3 43mm 国际版
+3 -1
View File
@@ -279,10 +279,12 @@
`CPH2583`: OnePlus 12 North America `CPH2583`: OnePlus 12 North America
**OnePlus Ace 3 / OnePlus 12R (`aston`) / OnePlus Ace 3 Genshin Impact Edition / OnePlus 12R Genshin Impact Edition (`martin`):** **OnePlus Ace 3 (`aston`):**
`PJE110`: OnePlus Ace 3 China / Genshin Impact Edition `PJE110`: OnePlus Ace 3 China / Genshin Impact Edition
**OnePlus 12R (`aston`):**
`CPH2585`: OnePlus 12R India / Genshin Impact Edition `CPH2585`: OnePlus 12R India / Genshin Impact Edition
`CPH2609`: OnePlus 12R Europe / Global / Genshin Impact Edition `CPH2609`: OnePlus 12R Europe / Global / Genshin Impact Edition