优化连续追问的报价条件与订单指代

This commit is contained in:
2026-11-06 12:32:41 +08:00
parent 33e166b104
commit 0f01a4a833
16 changed files with 487 additions and 62 deletions
+108
View File
@@ -1,6 +1,7 @@
"""Statistics use explicit exception reasons and actual, order-level progress."""
import json
import re
from pathlib import Path
import sqlite3
import tempfile
@@ -48,6 +49,7 @@ class OrderStatisticsTests(unittest.TestCase):
model.assert_not_called()
self.assertEqual(events[-1],{'d':1},events)
self.assertNotIn('_order_list_state',str(events));self.assertNotIn('_customer_data',str(events))
self.assertNotIn('_order_reference',str(events))
self.assertNotIn('SECRET',str(events));self.assertNotIn('不能泄露',str(events))
return events[0]
@@ -155,6 +157,112 @@ class OrderStatisticsTests(unittest.TestCase):
self.assertIn('7 票明确标记异常',text)
self.assertEqual(text.count('- 入仓码:'),5)
def test_subset_followups_keep_previous_stage_and_show_recorded_reasons(self):
self.assertTrue(self.ask('异常的呢')['login_required'])
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('已清关的订单有多少',cid)
text=self.ask('其中异常的呢',cid)['t']
self.assertIn('1 票当前节点为“已清关、可提柜”',text)
self.assertIn('等待客户资料',text)
self.assertNotIn('待核实资料',text)
self.assertIn('1 票当前节点',self.ask('这些一共多少票',cid)['t'])
text=self.ask('异常原因呢',cid)['t']
self.assertIn('等待客户资料',text)
self.assertNotIn('业务状态:',text)
self.assertIn('共1票',self.ask('查看全部',cid)['t'])
def test_ordinal_uses_the_displayed_reply_even_when_new_orders_arrive(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
text=self.ask('我有多少异常订单',cid)['t']
shown=re.findall(r'^- 入仓码:([^;]+);订单号:([^;]+);',text,re.M)
with self.app.app_context():
c=db.connect()
order_data.import_records(c,[{'tenant_id':'a','order_no':'NEWEST20260001','inbound_code':'NEWESTIN20260001',
'status':'PROCESSING','source_updated_at':'2030-01-01','exception_reason':'新记录'}])
c.commit();c.close()
card=self.ask('第一票的轨迹',cid)['card']
self.assertEqual(card['no'],shown[0][1])
card=self.ask('第二个呢',cid)['card']
self.assertEqual(card['no'],shown[1][1])
self.assertNotIn('NEWEST',str(card))
def test_selected_order_survives_acknowledgements_and_long_detail_followups(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('我有多少异常订单',cid)
first=self.ask('第一个呢',cid)['card']['no']
for _ in range(8):
self.ask('谢谢',cid)
text=self.ask('异常原因呢',cid)['t']
self.assertNotIn('请提供',text)
self.assertEqual(self.ask('重量呢',cid)['card']['no'],first)
def test_empty_or_out_of_range_ordinals_never_choose_an_unshown_order(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('我有多少异常订单',cid)
self.assertIn('展示了5票',self.ask('第6票的轨迹',cid)['t'])
self.ask('已还柜的订单有多少',cid)
self.assertIn('当前列表没有',self.ask('第一个呢',cid)['t'])
self.assertIn('0 票当前节点为“已还柜”',self.ask('到哪了',cid)['t'])
def test_ordinals_and_subsets_require_the_current_owned_topic_and_login(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('我有多少异常订单',cid)
self.ask('美国30KG海运报价',cid)
text=self.ask('第一票的轨迹',cid)['t']
self.assertIn('请先查看',text)
self.assertNotIn('INSTAT',text)
self.ask('我有多少异常订单',cid)
self.client.post('/api/customer/logout')
self.assertTrue(self.ask('第一个呢',cid)['login_required'])
self.assertTrue(self.ask('其中异常的呢',cid)['login_required'])
def test_conflicting_subset_conditions_request_a_scope_change(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('已清关的订单有多少',cid)
self.assertIn('确认要切换筛选条件',self.ask('其中已到港的呢',cid)['t'])
self.assertIn('10 票当前节点',self.ask('那已到港的呢',cid)['t'])
def test_subset_clarification_keeps_the_original_scope_for_the_next_answer(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('已清关的订单有多少',cid)
self.assertIn('请明确',self.ask('其中今天的异常呢',cid)['t'])
self.assertIn('1 票当前节点',self.ask('其中异常的呢',cid)['t'])
def test_a_shipping_quote_starting_with_these_is_a_new_quote_topic(self):
from logistics_chat.quote_data import import_snapshot
from test_quotes import fixture_snapshot
with self.app.app_context():
c=db.connect();import_snapshot(c,fixture_snapshot(),activate=True);c.commit();c.close()
self.login();cid=self.client.post('/api/new_chat').json['id']
self.ask('我有多少个订单',cid)
text=self.ask('这些货物美国30KG海运报价',cid)['t']
self.assertIn('美国 30KG',text)
self.assertNotIn('订单范围',text)
self.assertIn('请先查看',self.ask('第一个订单呢',cid)['t'])
def test_legacy_list_state_can_resolve_ordinals_without_saved_identifiers(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
text=self.ask('我有多少异常订单',cid)['t']
first=re.findall(r'^- 入仓码:([^;]+);订单号:([^;]+);',text,re.M)[0][1]
with self.app.app_context():
c=db.connect()
state=json.loads(c.execute('SELECT order_list_state FROM chat_history WHERE id=?',(cid,)).fetchone()[0])
del state['shown']
c.execute('UPDATE chat_history SET order_list_state=? WHERE id=?',(json.dumps(state),cid))
c.commit();c.close()
self.assertEqual(self.ask('第一个呢',cid)['card']['no'],first)
def test_ordinal_uses_saved_identifiers_when_a_field_contains_display_separators(self):
self.login();cid=self.client.post('/api/new_chat').json['id']
with self.app.app_context():
c=db.connect()
order_data.import_records(c,[{'tenant_id':'a','order_no':'STRUCTURED20260001',
'inbound_code':'VALUE;订单号:OTHER20260001','status':'PROCESSING',
'source_updated_at':'2030-01-01','exception_reason':'待核实'}])
c.commit();c.close()
self.ask('我有多少异常订单',cid)
self.assertEqual(self.ask('第一个呢',cid)['card']['no'],'STRUCTURED20260001')
def test_ambiguous_speech_answers_the_clear_count_and_requests_the_missing_meaning(self):
self.login()
text=self.ask('当前,我的订单有多少条,一层有多少条?')['t']
+1 -1
View File
@@ -114,7 +114,7 @@ class QuoteBusinessTests(unittest.TestCase):
text=self.ask('海运和空运哪个好,美国30KG')
self.assertIn('没有美国空运费率',text)
text=self.ask('美国美西海派多久')
self.assertIn('提取不等于送达',text);self.assertNotIn('元/KG',text)
self.assertIn('按开船后到提取计算',text);self.assertNotIn('元/KG',text)
text=self.ask('Please quote 30kg to US by sea')
self.assertIn('CNY/kg',text)
self.assertFalse(__import__('re').search(r'[\u4e00-\u9fff]',text),text)
+116
View File
@@ -119,3 +119,119 @@ class QuoteTimingTests(unittest.TestCase):
self.assertIn('最快参考方案暂时无法确定',text)
self.assertIn('最慢参考方案暂时无法确定',text)
self.assertNotIn('1000KG =',text)
def test_selected_route_survives_total_calculation_time_and_tax_questions(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国1000KG义乌美东海运,便宜的报价',cid)
for question in ('那一共多少钱','怎么算出来的'):
text=self.ask(question,cid)
self.assertIn('普船海派',text)
self.assertIn('1000KG = 6000元',text)
self.assertNotIn('美森正班海派',text)
text=self.ask('多快能到',cid)
self.assertIn('普船海派',text)
self.assertIn('船开后25-30天左右提取',text)
self.assertNotIn('美森正班海派',text)
self.assertIn('标注包税',self.ask('含税吗',cid))
text=self.ask('具体多少',cid)
self.assertIn('1000KG = 6000元',text)
self.assertNotIn('美森正班海派',text)
text=self.ask('全部渠道报价',cid)
self.assertIn('美森正班海派',text)
self.assertIn('普船海派',text)
def test_polite_acknowledgements_keep_quote_conditions_and_selection(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国30KG义乌美西最快海派报价',cid)
for question in ('谢谢','好的,谢谢您','OK'):
self.ask(question,cid)
text=self.ask('改成50KG呢',cid)
self.assertIn('美森正班海派 · 义乌',text)
self.assertIn('50KG = 400元',text)
self.assertNotIn('普船海派',text)
text=self.ask('所有箱都是普通货',cid)
self.assertIn('最快参考方案',text)
self.assertNotIn('普船海派',text)
def test_missing_weight_unit_stays_pending_until_an_explicit_unit_is_supplied(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国1000KG义乌美西海运最快报价',cid)
for question in ('重量改成800,其他不变','换成华南','谢谢','美东呢'):
text=self.ask(question,cid)
if question!='谢谢':
self.assertIn('单位',text)
self.assertNotIn('1000KG =',text)
text=self.ask('单位是KG',cid)
self.assertIn('美森正班海派 · 华南',text)
self.assertIn('800KG = 8000元',text)
self.assertNotIn('1000KG',text)
self.assertIn('800KG = 8000元',self.ask('具体多少',cid))
def test_quote_resume_is_explicit_and_survives_later_field_edits(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国30KG义乌美西最快报价',cid)
self.ask('我有多少个订单',cid)
text=self.ask('50KG呢',cid)
self.assertNotIn('美森正班海派',text)
text=self.ask('回到刚才的报价',cid)
self.assertIn('30KG = 240元',text)
self.assertNotIn('50KG',text)
text=self.ask('换成华南',cid)
self.assertIn('美森正班海派 · 华南',text)
self.assertIn('30KG = 240元',text)
def test_resume_does_not_recover_us_conditions_across_a_new_country_quote(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国30KG义乌海运报价',cid)
with self.app.app_context():
db.save_message(cid,'user','新的一票100KG发德国海运报价')
db.save_message(cid,'assistant','请核对对应目的地的报价。')
self.ask('我有多少个订单',cid)
text=self.ask('回到刚才的报价',cid)
self.assertIn('目的国家',text)
self.assertNotIn('美国 30KG',text)
self.assertNotIn('元/KG',text)
def test_new_quote_with_a_topic_switch_becomes_the_next_followup_root(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国30KG义乌美西最快报价',cid)
self.ask('换个话题,美国50KG华南美东海运报价',cid)
text=self.ask('最慢的呢',cid)
self.assertIn('普船海派 · 华南',text)
self.assertIn('50KG = 300元',text)
self.assertNotIn('30KG',text)
self.ask('另外问美国海运报价',cid)
text=self.ask('20KG呢',cid)
self.assertIn('美国 20KG',text)
self.assertIn('义乌',text)
self.assertNotIn('50KG',text)
def test_explicit_selection_and_business_question_are_retained_independently(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国1000KG义乌美东海运报价',cid)
self.assertIn('标注包税',self.ask('最快的含税吗',cid))
text=self.ask('那一共多少钱',cid)
self.assertIn('1000KG = 10000元',text)
self.assertNotIn('普船海派',text)
text=self.ask('最快多久能提取',cid)
self.assertIn('15天左右提取',text)
self.assertNotIn('普船海派',text)
def test_missing_weight_units_before_a_destination_do_not_reuse_the_old_weight(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国1000KG义乌美西最快海运报价',cid)
self.assertIn('单位',self.ask('重量改成800美东,其他不变',cid))
text=self.ask('KG',cid)
self.assertIn('800KG = 8000元',text)
self.assertNotIn('1000KG',text)
def test_all_channels_clears_the_named_service_and_keeps_origin_destination_weight(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('美国1000KG义乌美东普船海派最便宜报价',cid)
text=self.ask('全部渠道报价',cid)
self.assertIn('美森正班海派',text)
self.assertIn('合德海派',text)
self.assertIn('普船海派',text)
self.assertIn('1000KG = 10000元',text)
self.assertNotIn('华南',text)
self.assertNotIn('美西 ',text)