feat: add pinyin initial abbr helper for CRM names.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-07 16:57:05 +08:00
1 parent 65ea371d5f
commit fa9b3429c7
3 files changed
+133

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
"""名称拼音首字母缩写:库内存小写,检索时大小写不敏感。"""
from __future__ import annotations
import re
from typing import Optional
from pypinyin import Style, lazy_pinyin
_MAX_LEN = 100
_ALNUM = re.compile(r"[a-zA-Z0-9]")
def normalize_name_pinyin_abbr(value: Optional[str]) -> str:
raw = (value or "").strip().lower()
if not raw:
return ""
return raw[:_MAX_LEN]
def build_name_pinyin_abbr(name: Optional[str]) -> str:
text = (name or "").strip()
if not text:
return ""
parts: list[str] = []
for ch in text:
if "\u4e00" <= ch <= "\u9fff":
pys = lazy_pinyin(ch, style=Style.FIRST_LETTER)
if pys and pys[0]:
parts.append(str(pys[0]).lower()[0])
elif _ALNUM.match(ch):
parts.append(ch.lower())
# else: drop punctuation / spaces / % / brackets
return "".join(parts)[:_MAX_LEN]
def resolve_name_pinyin_abbr(
*,
name: Optional[str],
submitted: Optional[str] = None,
existing: Optional[str] = None,
submitted_provided: bool = False,
) -> Optional[str]:
"""保存时解析拼音字段。
- submitted_provided=True:用提交值(空则按 name 生成)
- 否则:已有非空 existing 则保留;existing 空则按 name 生成
"""
if submitted_provided:
normalized = normalize_name_pinyin_abbr(submitted)
if normalized:
return normalized
generated = build_name_pinyin_abbr(name)
return generated or None
existing_norm = normalize_name_pinyin_abbr(existing)
if existing_norm:
return existing_norm
generated = build_name_pinyin_abbr(name)
return generated or None
+1
View File
@@ -18,3 +18,4 @@ Pillow>=10.0.0
requests>=2.31.0
openpyxl>=3.1.0
alibabacloud_ocr_api20210707>=3.1.3
pypinyin>=0.53.0
+74
View File
@@ -0,0 +1,74 @@
from app.utils.pinyin_abbr import (
build_name_pinyin_abbr,
normalize_name_pinyin_abbr,
resolve_name_pinyin_abbr,
)
def test_empty_and_whitespace():
assert build_name_pinyin_abbr("") == ""
assert build_name_pinyin_abbr(" ") == ""
assert normalize_name_pinyin_abbr(None) == ""
assert normalize_name_pinyin_abbr(" AbC ") == "abc"
def test_chinese_and_alnum():
# pypinyin FIRST_LETTER: 工g业y硫l酸s(非设计稿中的 gylls)
assert build_name_pinyin_abbr("55% 工业硫酸") == "55gyls"
# pypinyin: 苯b骈p三s氮d唑z + BTA(非设计稿中的 bstnzbta)
assert build_name_pinyin_abbr("苯骈三氮唑BTA") == "bpsdzbta"
assert build_name_pinyin_abbr("PAC") == "pac"
def test_truncate_to_100():
long_name = "测" * 120
out = build_name_pinyin_abbr(long_name)
assert len(out) == 100
def test_resolve_submitted_provided_nonempty():
assert (
resolve_name_pinyin_abbr(
name="工业硫酸",
submitted=" CustomAbbr ",
existing="old",
submitted_provided=True,
)
== "customabbr"
)
def test_resolve_submitted_provided_empty_generates():
assert (
resolve_name_pinyin_abbr(
name="PAC",
submitted=" ",
existing="old",
submitted_provided=True,
)
== "pac"
)
def test_resolve_not_submitted_keeps_existing():
assert (
resolve_name_pinyin_abbr(
name="工业硫酸",
submitted=None,
existing=" KeepMe ",
submitted_provided=False,
)
== "keepme"
)
def test_resolve_not_submitted_empty_existing_generates():
assert (
resolve_name_pinyin_abbr(
name="PAC",
submitted=None,
existing="",
submitted_provided=False,
)
== "pac"
)