陆运选项不全时改为复制填空清单,方便销售按编号回填。
停发填写样例图,同群只跟当前工单,重量体积统一为 KG/CBM。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -24,8 +24,8 @@ AIR_REQUIRED_FIELDS = (
|
||||
("目的港", "目的地"),
|
||||
("品名", "品名"),
|
||||
("件数", "件数"),
|
||||
("毛重", "重量"),
|
||||
("体积", "体积"),
|
||||
("毛重", "重量(KG)"),
|
||||
("体积", "体积(CBM)"),
|
||||
("包装方式", "包装类型"),
|
||||
("报价日期", "报价日期"),
|
||||
)
|
||||
@@ -65,8 +65,8 @@ LAND_DISPLAY = {
|
||||
"起运港": "始发站",
|
||||
"目的港": "目的地",
|
||||
"品名": "货物品名",
|
||||
"毛重": "重量",
|
||||
"体积": "体积",
|
||||
"毛重": "重量(KG)",
|
||||
"体积": "体积(CBM)",
|
||||
"车型/数量": "车型/数量",
|
||||
"通关口岸": "通关口岸",
|
||||
"报价日期": "报价日期",
|
||||
@@ -178,6 +178,20 @@ _RE_WEIGHT_WORD = re.compile(r"(?:毛重|重量)\s*[::]?\s*(\d+(?:\.\d+)?)")
|
||||
_RE_VOLUME_WORD = re.compile(r"体积\s*[::]?\s*(\d+(?:\.\d+)?)")
|
||||
# 销售原话里的包装词:当前句出现则覆盖旧值,散货也要收下
|
||||
_PACK_WORDS = ("纸箱", "木箱", "托盘", "卡板", "散货")
|
||||
# 销售口中的报价日期。内部键仍是报价日期。货好时间、提货地址不是这里。
|
||||
QUOTE_DATE_SYNONYMS = (
|
||||
"询价日期",
|
||||
"走货日期",
|
||||
"询价时间",
|
||||
"走货时间",
|
||||
"发货时间",
|
||||
"发货日期",
|
||||
"出货日期",
|
||||
"出货时间",
|
||||
"提货时间",
|
||||
"提货日期",
|
||||
)
|
||||
|
||||
# 报价日期:9月15日 / 2026-09-15;未写年用上海当年
|
||||
_RE_DATE_YMD = re.compile(
|
||||
r"(20\d{2})\s*[-/.年]\s*(\d{1,2})\s*[-/.月]\s*(\d{1,2})\s*[日号]?"
|
||||
@@ -193,8 +207,10 @@ _ALIASES = {
|
||||
"始发站": "起运港",
|
||||
"货物品名": "品名",
|
||||
"重量(KG)": "毛重",
|
||||
"重量(KG)": "毛重",
|
||||
"重量": "毛重",
|
||||
"体积(CBM)": "体积",
|
||||
"体积(CBM)": "体积",
|
||||
"车型/数量": "车型/数量",
|
||||
"车型数量": "车型/数量",
|
||||
"数量": "数量",
|
||||
@@ -220,6 +236,8 @@ _ALIASES = {
|
||||
"贸易条款(非必填)": "贸易条款",
|
||||
"起运港(非必填)": "起运港",
|
||||
}
|
||||
for _quote_alias in QUOTE_DATE_SYNONYMS:
|
||||
_ALIASES[_quote_alias] = "报价日期"
|
||||
|
||||
|
||||
def shanghai_today() -> str:
|
||||
@@ -239,6 +257,7 @@ def normalize_facts(facts: dict[str, Any] | None) -> dict[str, str]:
|
||||
for raw_key, raw_val in (facts or {}).items():
|
||||
key = str(raw_key).strip()
|
||||
key = re.sub(r"(必填)|(非必填)|\(必填\)|\(非必填\)", "", key).strip()
|
||||
key = re.sub(r"(KG)|(CBM)|\(KG\)|\(CBM\)", "", key, flags=re.I).strip()
|
||||
key = _ALIASES.get(key, key)
|
||||
if raw_val is None:
|
||||
continue
|
||||
@@ -285,6 +304,32 @@ def _harvest_packaging(raw: str) -> str:
|
||||
return last
|
||||
|
||||
|
||||
def _quote_date_labeled_value(raw: str) -> str:
|
||||
"""
|
||||
原话里「报价日期」或同义词后面的值。
|
||||
|
||||
询价日期、走货日期、发货时间、提货日期等都算报价日期。
|
||||
能写成 yyyy-MM-dd 就规范;「明天」这类留原文。
|
||||
没有这些标签则空串,交给句子里的裸日期。
|
||||
同一句出现多次,用最后一次,避免前面的货好时间把日期抢走。
|
||||
"""
|
||||
text = raw or ""
|
||||
labels = ("报价日期",) + QUOTE_DATE_SYNONYMS
|
||||
best_at = -1
|
||||
best_val = ""
|
||||
for label in labels:
|
||||
pattern = re.compile(
|
||||
rf"(?<![\u4e00-\u9fffA-Za-z0-9]){re.escape(label)}\s*[::]?\s*(\S+)"
|
||||
)
|
||||
for hit in pattern.finditer(text):
|
||||
if hit.start() >= best_at:
|
||||
best_at = hit.start()
|
||||
best_val = hit.group(1).strip().strip(",,。;;、")
|
||||
if not best_val:
|
||||
return ""
|
||||
return _harvest_quote_date(best_val) or best_val
|
||||
|
||||
|
||||
def _harvest_quote_date(raw: str) -> str:
|
||||
"""当前原话里的报价日期,规范成 yyyy-MM-dd;没有则空串。"""
|
||||
from datetime import datetime
|
||||
@@ -304,15 +349,26 @@ def _harvest_quote_date(raw: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
_RE_CLARIFY_EXAMPLE = re.compile(r"^\s*[((]如\s*[::]")
|
||||
|
||||
|
||||
def _without_clarify_examples(text: str) -> str:
|
||||
"""补问清单里的「(如:托盘、散货)」整行丢掉,避免示例被当成已填。"""
|
||||
return "\n".join(
|
||||
line for line in (text or "").splitlines() if not _RE_CLARIFY_EXAMPLE.match(line)
|
||||
)
|
||||
|
||||
|
||||
def harvest_oral_measures(text: str, facts: dict[str, str] | None = None) -> dict[str, str]:
|
||||
"""
|
||||
从当前原话机读件数/重量/体积/包装/报价日期。
|
||||
|
||||
当前句写了的覆盖旧值:散货替换托盘,9月16日写入报价日期。
|
||||
补问复制清单的示例行不参与机读。
|
||||
副作用:无。不改主账。不猜港口。
|
||||
"""
|
||||
merged = dict(facts or {})
|
||||
raw = text or ""
|
||||
raw = _without_clarify_examples(text or "")
|
||||
hit = _RE_PIECES.search(raw)
|
||||
if hit:
|
||||
merged["件数"] = f"{hit.group(1)}{hit.group(2)}"
|
||||
@@ -334,9 +390,13 @@ def harvest_oral_measures(text: str, facts: dict[str, str] | None = None) -> dic
|
||||
pack = _harvest_packaging(raw)
|
||||
if pack:
|
||||
merged["包装方式"] = pack
|
||||
quote_date = _harvest_quote_date(raw)
|
||||
if quote_date:
|
||||
merged["报价日期"] = quote_date
|
||||
labeled_date = _quote_date_labeled_value(raw)
|
||||
if labeled_date:
|
||||
merged["报价日期"] = labeled_date
|
||||
else:
|
||||
quote_date = _harvest_quote_date(raw)
|
||||
if quote_date:
|
||||
merged["报价日期"] = quote_date
|
||||
from agent.schema.tms_air_query import harvest_named_air_route
|
||||
|
||||
return harvest_named_air_route(raw, merged)
|
||||
@@ -405,6 +465,25 @@ def pick_collab_from_facts(
|
||||
return out
|
||||
|
||||
|
||||
def air_general_cargo_collab_defaults(facts: dict[str, str] | None) -> dict[str, str]:
|
||||
"""
|
||||
空运货物品名正好是「普货」时,含电、含磁缺省为否。
|
||||
|
||||
只补事实里还没写的项。已经写了「是」或「否」的不在这里改。
|
||||
品名多一个字(如普货纸箱)不算普货,不默认。
|
||||
调用方仍须遵守:群里已记下的协同值优先,本函数只给空项。
|
||||
"""
|
||||
src = normalize_facts(facts)
|
||||
if (src.get("品名") or "").strip() != "普货":
|
||||
return {}
|
||||
out: dict[str, str] = {}
|
||||
for key in AIR_COLLAB_FIELDS:
|
||||
# 摘要占位「-」等于没写,不能挡住默认否。
|
||||
if (src.get(key) or "").strip() in {"", "-", "—", "-"}:
|
||||
out[key] = "否"
|
||||
return out
|
||||
|
||||
|
||||
def harvest_oral_collab(text: str) -> dict[str, str]:
|
||||
"""
|
||||
群里口语协同:含油/含电/含磁、货好时间、是否为危险品。
|
||||
|
||||
Reference in New Issue
Block a user