93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
"""Server-side mirror of the frontend agent-name desensitization map.
|
|
|
|
The web UI displays agent names through a static term→abbreviation map
|
|
(``frontend-web/src/lib/desensitize.ts``) — e.g. the stored name "态势分析" is
|
|
shown as "TS分析". The gallery search box therefore matches against the
|
|
*desensitized* display form, not the raw stored name.
|
|
|
|
When search moves server-side (paginated listing), the backend must match the
|
|
same way, so this module mirrors that static map verbatim. The frontend map is
|
|
never extended at runtime (``addDesensitizeEntries`` is defined but never
|
|
called), so a static copy stays in sync.
|
|
|
|
Used by the SQL listing query to match "raw name OR desensitized name".
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# Mirror of DESENSITIZE_MAP in frontend-web/src/lib/desensitize.ts.
|
|
# Keep entries identical to the frontend so server-side and client-side search
|
|
# behave the same. Order does not affect membership tests.
|
|
DESENSITIZE_MAP: dict[str, str] = {
|
|
"态势": "TS",
|
|
"你好": "nh",
|
|
"滨海作战体系": "第一张网",
|
|
"滨海作战部队": "第一张网",
|
|
"Taiwan Air Force Flight Units": "第二张网",
|
|
"台海空军飞行部队": "第二张网",
|
|
"空军": "KJ",
|
|
"海军": "HJ",
|
|
"陆军": "LJ",
|
|
"陆战队": "LZD",
|
|
"海巡": "HX",
|
|
"憲兵": "XB",
|
|
"資通電軍": "ZTDJ",
|
|
"情报": "QB",
|
|
"指挥": "ZH",
|
|
"信息准备": "XX准备",
|
|
"行为体": "XWT",
|
|
"驱动因素": "QDYS",
|
|
"叙事": "XS",
|
|
"前三定": "QSD",
|
|
"受众目标": "SZMB",
|
|
"作战": "ZZ",
|
|
"目的": "MD",
|
|
"关键传播节点": "GJCBJD",
|
|
"战法": "ZF",
|
|
"行动": "XD",
|
|
"打击": "DJ",
|
|
"目标": "MB",
|
|
"战力": "ZL",
|
|
"筹划": "COH",
|
|
"策划": "CEH",
|
|
"模拟": "MN",
|
|
"推演": "TY",
|
|
"认知": "RZ",
|
|
"触及": "CJ",
|
|
"军": "J",
|
|
"美军": "MJ",
|
|
"台军": "TJ",
|
|
}
|
|
|
|
|
|
def desensitize_name(name: str) -> str:
|
|
"""Return ``name`` with every mapped term replaced by its abbreviation.
|
|
|
|
Mirrors the frontend ``desensitize()`` — a sequence of literal replacements.
|
|
"""
|
|
out = name
|
|
for term, abbr in DESENSITIZE_MAP.items():
|
|
if term in out:
|
|
out = out.replace(term, abbr)
|
|
return out
|
|
|
|
|
|
def name_matches(name: str, needle: str) -> bool:
|
|
"""True when ``needle`` (case-insensitive) is in the raw OR desensitized name."""
|
|
n = needle.strip().lower()
|
|
if not n:
|
|
return True
|
|
return n in name.lower() or n in desensitize_name(name).lower()
|
|
|
|
|
|
def source_terms_for_needle(needle: str) -> list[str]:
|
|
"""Return the raw source terms whose abbreviation contains ``needle``.
|
|
|
|
Lets the SQL search add ``name LIKE %term%`` clauses so a user typing an
|
|
abbreviation (e.g. "TS") still matches the stored raw term (e.g. "态势").
|
|
"""
|
|
n = needle.strip().lower()
|
|
if not n:
|
|
return []
|
|
return [term for term, abbr in DESENSITIZE_MAP.items() if n in abbr.lower()]
|