陆运选项不全时改为复制填空清单,方便销售按编号回填。

停发填写样例图,同群只跟当前工单,重量体积统一为 KG/CBM。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-23 17:10:13 +08:00
co-authored by Cursor
parent 2334524bb8
commit 378bb892b3
33 changed files with 1204 additions and 265 deletions
+64 -3
View File
@@ -15,7 +15,12 @@ if ROOT not in sys.path:
os.environ.setdefault("LEDGER_BACKEND", "memory")
from agent.llm.extract_text import extract_inquiry_snapshot, parse_labeled_facts
from agent.llm.extract_text import (
detect_transport_mode,
extract_inquiry_snapshot,
parse_labeled_facts,
)
from agent.schema.field_validate import normalize_facts
from agent.llm.mode_extract_fields import invoke_shell, parse_extract_payload
from agent.policy.air_text_flow import AirTextInquiryFlow
from agent.ledger.memory_ledger import MemoryLedger
@@ -260,7 +265,7 @@ class OralExtractTests(unittest.TestCase):
work_order_no="WO1",
facts={**facts, "起运港": "南京", "目的港": "吉隆坡", "品名": "茶叶", "件数": "10"},
)
self.assertIn("重量:1.5KG", shown)
self.assertIn("重量(KG):1.5KG", shown)
self.assertNotIn("1.5KGS", shown)
def test_oral_units_fill_weight_volume_without_b(self) -> None:
@@ -326,6 +331,36 @@ class OralExtractTests(unittest.TestCase):
self.assertIn("目的地:洛杉矶", joined)
self.assertNotIn("【询价卡片】", joined)
def test_mode_index_maps_land_sea_air(self) -> None:
self.assertEqual(detect_transport_mode("1"), "LAND")
self.assertEqual(detect_transport_mode("2"), "SEA")
self.assertEqual(detect_transport_mode("3"), "AIR")
self.assertEqual(detect_transport_mode("1.陆运"), "LAND")
self.assertEqual(detect_transport_mode("空运"), "AIR")
self.assertEqual(detect_transport_mode("10件"), "")
self.assertEqual(detect_transport_mode("1.件数(必填):10"), "")
class ClarifyPasteTests(unittest.TestCase):
def test_paste_numbered_required_lines_and_skip_examples(self) -> None:
"""复制补问清单:只收冒号后的值,示例行和空项都不算填了。"""
text = """
1.件数(必填):10
(如:10)
2.重量(KG)(必填):10
(如:100)
3.体积(CBM)(必填):10
(如:2)
4.包装类型(必填):
(如:托盘、散货)
"""
facts = normalize_facts(parse_labeled_facts(text))
self.assertEqual(facts.get("件数"), "10")
self.assertEqual(facts.get("毛重"), "10")
self.assertEqual(facts.get("体积"), "10")
self.assertNotIn("包装方式", facts)
self.assertNotEqual(facts.get("包装方式"), "托盘、散货")
class ImageOptionalClipTests(unittest.TestCase):
def test_numbered_extra_lines_do_not_enter_fields(self) -> None:
@@ -361,7 +396,7 @@ class ImageOptionalClipTests(unittest.TestCase):
transport_mode="空运",
)
self.assertNotIn("希望送到", card)
self.assertNotIn("4.", card)
self.assertNotIn("4. 希望送到", card)
self.assertIn("收货地址", card)
@@ -435,6 +470,32 @@ class SeaSheetHeaderClipTests(unittest.TestCase):
self.assertNotIn("送货地址", facts.get("整柜或拼柜") or "")
self.assertNotIn("抵达", facts.get("箱型箱量") or "")
def test_quote_date_synonyms_for_sea_land_air(self) -> None:
"""询价/走货/发货/出货/提货的日期或时间,海运陆运空运都记成报价日期。"""
from agent.schema.field_validate import QUOTE_DATE_SYNONYMS, normalize_facts
modes = (("海运", "SEA"), ("陆运", "LAND"), ("空运", "AIR"))
for label in QUOTE_DATE_SYNONYMS:
self.assertEqual(normalize_facts({label: "2026-09-23"})["报价日期"], "2026-09-23")
for word, mode in modes:
snap = extract_inquiry_snapshot(f"{word}\n{label}:2026-09-23", allow_b=False)
self.assertEqual(snap["business_line"], mode, label)
self.assertEqual(snap["facts"].get("报价日期"), "2026-09-23", label)
self.assertNotIn(label, snap["facts"])
def test_quote_date_synonym_does_not_steal_ready_or_pickup(self) -> None:
"""货好时间、提货地址仍是原字段;同义词日期不被前面的日期抢走。"""
snap = extract_inquiry_snapshot(
"海运\n货好时间:9月20日\n提货地址:上海仓库\n询价日期:2026-09-15",
allow_b=False,
)
facts = snap["facts"]
self.assertEqual(facts.get("报价日期"), "2026-09-15")
self.assertEqual(facts.get("货好时间"), "9月20日")
self.assertEqual(facts.get("提货地址"), "上海仓库")
oral = extract_inquiry_snapshot("空运 发货日期9月15日", allow_b=False)
self.assertEqual(oral["facts"].get("报价日期"), "2026-09-15")
if __name__ == "__main__":
unittest.main()