海运补问保留贸易条款;陆运多车型价表按列回填,车型码不进起始地
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -169,15 +169,35 @@ ALL_COLLAB_KEYS = tuple(
|
||||
|
||||
# 口语里已经带上 TMS 文档规定的单位时,补进空字段。
|
||||
# 只认「数字+单位」,不猜港口,不把长宽高换算成立方。
|
||||
_RE_PIECES = re.compile(r"(?<![\d.])(\d+)\s*(件|pcs)\b", re.I)
|
||||
_RE_WEIGHT = re.compile(r"(?<![\d.])(\d+(?:\.\d+)?)\s*(kgs|kg|公斤|千克)\b", re.I)
|
||||
# 单位后不用 Unicode \b:CBM/KG 紧贴中文时 \w 含汉字,\b 不成立会整段漏抽。
|
||||
_RE_PIECES = re.compile(r"(?<![\d.])(\d+)\s*(件|pcs)(?![A-Za-z0-9])", re.I)
|
||||
_RE_WEIGHT = re.compile(
|
||||
r"(?<![\d.])(\d+(?:\.\d+)?)\s*(kgs|kg|公斤|千克)(?![A-Za-z0-9])",
|
||||
re.I,
|
||||
)
|
||||
_RE_VOLUME = re.compile(
|
||||
r"(?<![\d.])(\d+(?:\.\d+)?)\s*(cbm|立方米|立方|m3|m³)\b",
|
||||
r"(?<![\d.])(\d+(?:\.\d+)?)\s*(cbm|立方米|立方|m3|m³)(?![A-Za-z0-9])",
|
||||
re.I,
|
||||
)
|
||||
_RE_VOLUME_FANG = re.compile(r"(?<![\d.])(\d+(?:\.\d+)?)\s*方(?!向)")
|
||||
_RE_WEIGHT_WORD = re.compile(r"(?:毛重|重量)\s*[::]?\s*(\d+(?:\.\d+)?)")
|
||||
_RE_VOLUME_WORD = re.compile(r"体积\s*[::]?\s*(\d+(?:\.\d+)?)")
|
||||
# 销售常把小数点两侧空开,或误用全角点/中文句号:578. 5KG、1. 03CBM。
|
||||
# 只在后面跟重量/体积单位时收拢,避免误伤普通句号。
|
||||
_RE_BROKEN_DECIMAL = re.compile(
|
||||
r"(\d+)\s*[..。]\s*(\d+)(?=\s*(?:kgs?|公斤|千克|cbm|立方米|立方|m3|m³|方))",
|
||||
re.I,
|
||||
)
|
||||
|
||||
|
||||
def _glue_broken_decimals(text: str) -> str:
|
||||
"""
|
||||
把「578. 5KG」「1. 03CBM」收成「578.5KG」「1.03CBM」。
|
||||
|
||||
中英文句号/全角点两侧有空格时,机读否则只命中小数段变成 5KG/03CBM。
|
||||
副作用:无。不改主账。
|
||||
"""
|
||||
return _RE_BROKEN_DECIMAL.sub(r"\1.\2", text or "")
|
||||
# 销售原话里的包装词:当前句出现则覆盖旧值,散货也要收下
|
||||
_PACK_WORDS = ("纸箱", "木箱", "托盘", "卡板", "散货")
|
||||
# 销售口中的报价日期。内部键仍是报价日期。货好时间、提货地址不是这里。
|
||||
@@ -439,10 +459,12 @@ def harvest_oral_measures(text: str, facts: dict[str, str] | None = None) -> dic
|
||||
|
||||
当前句写了的覆盖旧值:散货替换托盘,9月16日写入报价日期。
|
||||
补问复制清单的示例行不参与机读。
|
||||
小数点两侧空格先收拢,再匹配单位。
|
||||
副作用:无。不改主账。不猜港口。
|
||||
"""
|
||||
merged = dict(facts or {})
|
||||
raw = _without_clarify_examples(text or "")
|
||||
raw0 = _without_clarify_examples(text or "")
|
||||
raw = _glue_broken_decimals(raw0)
|
||||
hit = _RE_PIECES.search(raw)
|
||||
if hit:
|
||||
merged["件数"] = f"{hit.group(1)}{hit.group(2)}"
|
||||
@@ -656,6 +678,27 @@ def looks_like_container_spec(text: str) -> bool:
|
||||
return bool(_CONTAINER_SPEC.search(text or ""))
|
||||
|
||||
|
||||
# 货量里除箱型外还有装满/吨等意图时,不能当「误写入的箱型」丢掉。
|
||||
_CARGO_QTY_INTENT = re.compile(
|
||||
r"装满|满柜|满载|吨|件|KG|KGS|CBM|立方|\d+\s*方|票|报价\s*\d|\d+\s*个价格",
|
||||
re.I,
|
||||
)
|
||||
|
||||
|
||||
def is_container_only_cargo_qty(text: str) -> bool:
|
||||
"""
|
||||
货量是否整段只是箱型箱量写法。
|
||||
|
||||
「40HQ*1」「1x40HQ」应从货量剔除;「40HQ、20GP 装满,报价2个价格」是销售在答货物数量,保留。
|
||||
"""
|
||||
raw = (text or "").strip()
|
||||
if not looks_like_container_spec(raw):
|
||||
return False
|
||||
if _CARGO_QTY_INTENT.search(raw):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def promote_land_vehicle_from_container(facts: dict[str, str] | None) -> dict[str, str]:
|
||||
"""
|
||||
陆运时把误落入「箱型箱量」的车型改写到「车型/数量」。
|
||||
@@ -697,18 +740,21 @@ def project_sea_cargo_qty(facts: dict[str, str] | None) -> dict[str, str]:
|
||||
海运货物数量投影。
|
||||
|
||||
抽字段常把「20件」放进件数,又把「40HQ*1」写进货量。
|
||||
货量只要长得像箱型,就丢掉,改用件数里的数量;件数也是箱型则不搬。
|
||||
箱型箱量空着时,把这串箱型补到箱型箱量。不限具体件数。
|
||||
货量若整段只是箱型写法,就丢掉,改用件数里的数量;件数也是箱型则不搬。
|
||||
「40HQ 装满」这类带货量意图的保留,不能再逼销售重填。
|
||||
箱型箱量空着时,把纯箱型串补到箱型箱量。不限具体件数。
|
||||
"""
|
||||
merged = dict(facts or {})
|
||||
qty = (merged.get("货量") or merged.get("货物数量") or "").strip()
|
||||
pieces = (merged.get("件数") or "").strip()
|
||||
if looks_like_container_spec(qty):
|
||||
if is_container_only_cargo_qty(qty):
|
||||
if not (merged.get("箱型箱量") or "").strip():
|
||||
merged["箱型箱量"] = qty
|
||||
merged.pop("货量", None)
|
||||
merged.pop("货物数量", None)
|
||||
qty = ""
|
||||
elif looks_like_container_spec(qty) and _CARGO_QTY_INTENT.search(qty):
|
||||
pass
|
||||
if not qty and pieces and not looks_like_container_spec(pieces):
|
||||
merged["货量"] = pieces
|
||||
return merged
|
||||
|
||||
Reference in New Issue
Block a user