Initialize clean CSR inventory repository
This commit is contained in:
104
inventory/cpu_catalog.py
Normal file
104
inventory/cpu_catalog.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CPU_VENDOR_CHOICES = (
|
||||
("intel", "Intel"),
|
||||
("amd", "AMD"),
|
||||
)
|
||||
|
||||
CPU_FAMILY_CHOICES = (
|
||||
("intel_i3", "Intel Core i3"),
|
||||
("intel_i5", "Intel Core i5"),
|
||||
("intel_i7", "Intel Core i7"),
|
||||
("intel_i9", "Intel Core i9"),
|
||||
("intel_ultra_5", "Intel Core Ultra 5"),
|
||||
("intel_ultra_7", "Intel Core Ultra 7"),
|
||||
("intel_ultra_9", "Intel Core Ultra 9"),
|
||||
("amd_ryzen_3", "AMD Ryzen 3"),
|
||||
("amd_ryzen_5", "AMD Ryzen 5"),
|
||||
("amd_ryzen_7", "AMD Ryzen 7"),
|
||||
("amd_ryzen_9", "AMD Ryzen 9"),
|
||||
("amd_ryzen_ai", "AMD Ryzen AI"),
|
||||
("amd_threadripper", "AMD Threadripper"),
|
||||
("amd_fx", "AMD FX"),
|
||||
)
|
||||
|
||||
|
||||
def _load_catalog() -> tuple[str, ...]:
|
||||
values = []
|
||||
for line in Path(__file__).with_name("cpu_models.txt").read_text(encoding="utf-8").splitlines():
|
||||
value = line.strip()
|
||||
if not value:
|
||||
continue
|
||||
if value.startswith("Core Ultra"):
|
||||
value = f"Intel {value}"
|
||||
values.append(value)
|
||||
return tuple(dict.fromkeys(values))
|
||||
|
||||
|
||||
CPU_MODELS = _load_catalog()
|
||||
|
||||
|
||||
def _tokens(value: str) -> list[str]:
|
||||
return re.findall(r"[a-z]+\d*|\d+[a-z]*", value.casefold())
|
||||
|
||||
|
||||
def _short_tokens(value: str) -> list[str]:
|
||||
tokens = _tokens(value)
|
||||
while tokens and tokens[0] in {"intel", "amd", "core"}:
|
||||
tokens.pop(0)
|
||||
return tokens
|
||||
|
||||
|
||||
def _match_score(model: str, term: str, preferred: bool) -> int:
|
||||
query_tokens = _tokens(term)
|
||||
if not query_tokens:
|
||||
return 100 if preferred else 1
|
||||
|
||||
model_tokens = _tokens(model)
|
||||
short_tokens = _short_tokens(model)
|
||||
query_text = " ".join(query_tokens)
|
||||
model_text = " ".join(model_tokens)
|
||||
short_text = " ".join(short_tokens)
|
||||
compact_query = "".join(query_tokens)
|
||||
compact_model = "".join(model_tokens)
|
||||
compact_short = "".join(short_tokens)
|
||||
|
||||
score = 0
|
||||
if query_text == model_text:
|
||||
score = 12_000
|
||||
elif query_text == short_text:
|
||||
score = 11_000
|
||||
elif compact_query in {compact_model, compact_short}:
|
||||
score = 10_000
|
||||
elif all(token in model_tokens for token in query_tokens):
|
||||
score = 9_000
|
||||
elif all(any(candidate.startswith(token) for candidate in model_tokens) for token in query_tokens):
|
||||
score = 8_000
|
||||
elif compact_query in compact_model:
|
||||
score = 7_000
|
||||
elif all(token in model_text for token in query_tokens):
|
||||
score = 6_000
|
||||
else:
|
||||
return 0
|
||||
|
||||
if preferred:
|
||||
score += 250
|
||||
score -= min(len(model), 200)
|
||||
return score
|
||||
|
||||
|
||||
def suggest_cpus(term: str, existing_values: Iterable[str] = (), limit: int = 15) -> list[str]:
|
||||
existing = {value.strip() for value in existing_values if value and value.strip()}
|
||||
candidates = list(dict.fromkeys([*existing, *CPU_MODELS]))
|
||||
ranked = [
|
||||
(_match_score(model, term, model in existing), index, model)
|
||||
for index, model in enumerate(candidates)
|
||||
]
|
||||
ranked = [item for item in ranked if item[0] > 0]
|
||||
ranked.sort(key=lambda item: (-item[0], item[1], item[2].casefold()))
|
||||
return [model for _, _, model in ranked[:limit]]
|
||||
Reference in New Issue
Block a user