空运「货交」只记提货地址,不再当成起运地。舱位旧说法「释放」先问航线是否取消,陆运通关口岸示例改为友谊关。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-11 20:45:53 +08:00
co-authored by Cursor
parent b070a9b7a7
commit 185abbf45e
16 changed files with 533 additions and 49 deletions
+64
View File
@@ -371,6 +371,68 @@ def _tighten_sheet_labels(text: str) -> str:
return body
# 「货交上海」是提货地址,不是起运地。地址/地、到/于只是口语粘连,不进地址正文。
_RE_CARGO_HANDOVER = re.compile(
r"货交\s*(?:地址|地)?\s*[::]?\s*(?:到|于|至|往)?\s*([^\n,,。;;]{1,60})"
)
# 同一行跟在地址后面的询价口头禅或下一栏字段,不是地址的一部分。
_RE_HANDOVER_TAIL = re.compile(
r"(?:\s+|,|,)?(?:看看价格|看一下价格|看价格|询价|报价|多少钱|多少|"
r"目的地|目的港|起运地|起运港|品名|件数|毛重|体积|包装|空运|海运|陆运).*$"
)
# 另有起运说法时保留起运地。先抠掉「货交…」,避免「货交到上海」被当成「到上海」。
_RE_EXPLICIT_ORIGIN = re.compile(
r"起运地|起运港|"
r"[A-Za-z]{3}\s*[-–—//]\s*[A-Za-z]{3}|"
r"[A-Za-z]{3}\s*(?:到|至)\s*[A-Za-z]{3}|"
r"从\s*\S{1,16}\s*(?:飞|到|至)|"
r"[\u4e00-\u9fff]{2,12}\s*飞|"
r"[\u4e00-\u9fff]{2,12}\s*到\s*[\u4e00-\u9fffA-Za-z]{2,12}"
)
def _handover_place(raw: str) -> str:
"""货交后面的地名。去掉口头禅和首尾标点,空的不当地址。"""
place = _RE_HANDOVER_TAIL.sub("", (raw or "").strip())
return place.strip(" ::,,。;;")
def _has_explicit_origin(text: str) -> bool:
"""原话里另写了起运地、三字码航线或「从哪飞/到」。货交那一段先拿掉。"""
stripped = _RE_CARGO_HANDOVER.sub(" ", text or "")
return _RE_EXPLICIT_ORIGIN.search(stripped) is not None
def apply_cargo_handover_synonym(
text: str,
facts: dict[str, str] | None,
*,
business_line: str = "",
) -> dict[str, str]:
"""
货交 = 提货地址。例:货交上海 → 提货地址上海。
只认原话里的「货交」,不把裸城市猜成港口。
空运且没有另写起运地时,清掉被误收成起运地的同一处地名,否则 TMS 会按错误起运查价。
海运/陆运只补提货地址,不动起运港。副作用:无。
"""
merged = dict(facts or {})
places: list[str] = []
for hit in _RE_CARGO_HANDOVER.finditer(text or ""):
place = _handover_place(hit.group(1))
if place and place not in places:
places.append(place)
if not places:
return merged
merged["提货地址"] = "、".join(places)
is_air = (business_line or "").strip().upper() == "AIR" or "空运" in (text or "")
if is_air and not _has_explicit_origin(text):
merged.pop("起运港", None)
merged.pop("起运地", None)
merged.pop("originCode", None)
return merged
def _drop_fee_place_values(facts: dict[str, str]) -> dict[str, str]:
"""起运地/目的地收成「操作费、文件费」时丢掉。那是费用栏,不是港口。"""
out = dict(facts or {})
@@ -407,6 +469,7 @@ def extract_inquiry_snapshot(
facts = harvest_oral_measures(text, normalize_facts(dict(injected_facts)))
facts = _merge_spoken_collab(text, facts)
facts = _merge_optional_inquiry_labels(text, facts)
facts = apply_cargo_handover_synonym(text, facts, business_line=mode)
for key in ("货好时间", "提货地址", "收货地址", "货源地", "贸易条款"):
if str(facts.get(key) or "").strip():
facts[key] = clip_inquiry_value(str(facts[key]))
@@ -453,6 +516,7 @@ def extract_inquiry_snapshot(
facts = harvest_oral_measures(text, normalize_facts(facts))
facts = _merge_spoken_collab(text, facts)
facts = _merge_optional_inquiry_labels(text, facts)
facts = apply_cargo_handover_synonym(text, facts, business_line=mode)
for key in ("货好时间", "提货地址", "收货地址", "货源地", "贸易条款"):
if str(facts.get(key) or "").strip():
facts[key] = clip_inquiry_value(str(facts[key]))