Files
baiyue-logistics-chat/tests/test_quote_timing.py
T

238 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Fast/slow comparisons preserve shipping conditions and comparable rate groups."""
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from logistics_chat import create_app, db
from logistics_chat.quote_data import import_snapshot
from logistics_chat.quote_engine import select_timed_rates
from test_quotes import fixture_snapshot, frames
def timing_snapshot():
book=fixture_snapshot()
rates=[]
for origin in ('义乌','华南'):
for zone,offset in (('美西',0),('美中',1),('美东',2)):
for service,price,eta in (('美森正班海派',8,'船开后15天左右'),
('合德海派',6,'船开后20-22天左右'),
('普船海派',4,'船开后25-30天左右')):
rates.append({'service':service,'kind':'parcel','origin':origin,'zone':zone,
'unit':'kg','tax':'included','min_weight':'12','price':str(price+offset),
'eta':eta,'destinations':[],'source_sheet':'合成时效','source_cell':'A1'})
book['rates']=rates
return book
class QuoteTimingTests(unittest.TestCase):
def setUp(self):
folder=tempfile.TemporaryDirectory();self.addCleanup(folder.cleanup)
root=Path(folder.name)
self.app=create_app({'TESTING':True,'DATABASE':root/'test.db','UPLOAD_DIR':root/'uploads',
'BACKUP_DIR':root/'backups','LOG_DIR':root/'logs','DEEPSEEK_API_KEY':'','RATE_LIMIT_PER_MIN':1000})
self.client=self.app.test_client()
self.client.post('/api/visitor/session',json={'key':'2'*64})
with self.app.app_context():
connection=db.connect()
import_snapshot(connection,timing_snapshot(),activate=True)
connection.commit();connection.close()
def ask(self,question,cid=None):
with patch('logistics_chat.ai_client.post_completion') as model:
events=frames(self.client.post('/stream_chat',json={'msg':question,'conv_id':cid}))
model.assert_not_called()
self.assertEqual(events[-1],{'d':1},events)
return events[0]['t']
def test_fastest_and_slowest_show_each_region_origin_and_the_correct_amount(self):
text=self.ask('我想发一批货,一吨发发到美国走海运,最快的和最慢的价格分别是多少?')
fast,slow=text.split('最慢参考方案')
self.assertIn('最快参考方案',fast)
self.assertIn('美西 8元/KG,1000KG = 8000元',fast)
self.assertIn('美东 10元/KG,1000KG = 10000元',fast)
self.assertIn('美森正班海派 · 华南',fast)
self.assertNotIn('普船海派',fast)
self.assertIn('美西 4元/KG,1000KG = 4000元',slow)
self.assertIn('美东 6元/KG,1000KG = 6000元',slow)
self.assertIn('船开后25-30天左右提取',slow)
self.assertNotIn('合德海派',text)
def test_short_followups_keep_weight_origin_zone_and_selected_comparison(self):
cid=self.client.post('/api/new_chat').json['id']
self.ask('1000KG到美国走海运,最快和最慢价格分别多少',cid)
for question in ('慢的呢?','义乌交仓','美东呢','请给我具体报价'):
text=self.ask(question,cid)
self.assertIn('美国 1000KG',text)
self.assertIn('最慢参考方案',text)
self.assertNotIn('最快参考方案',text)
self.assertNotIn('华南',text)
self.assertIn('1000KG = 6000元',text)
text=self.ask('50KG呢',cid)
self.assertIn('50KG = 300元',text)
self.assertNotIn('1000KG',text)
text=self.ask('全部渠道报价',cid)
self.assertIn('美森正班海派',text)
self.assertIn('合德海派',text)
self.assertNotIn('最慢参考方案',text)
text=self.ask('新的一批100KG发美国海运报价',cid)
self.assertIn('美国 100KG',text)
self.assertIn('华南',text)
self.assertNotIn('最慢参考方案',text)
def test_numeric_timing_groups_keep_destinations_tax_and_service_kinds_separate(self):
base={'zone':'美西','kind':'parcel','unit':'kg','tax':'included'}
rates=[{**base,'eta':'10-35天','service':'wide'},
{**base,'eta':'15-25天','service':'narrow'},
{**base,'zone':'美东','eta':'40-45天','service':'east'},
{**base,'tax':'excluded','eta':'20天','service':'excluded'},
{**base,'kind':'truck','eta':'50天','service':'truck'},
{**base,'eta':'未提供时效','service':'unknown'}]
self.assertEqual({r['service'] for r in select_timed_rates(rates)},
{'wide','east','excluded','truck'})
self.assertEqual({r['service'] for r in select_timed_rates(rates,slowest=True)},
{'wide','east','excluded','truck'})
self.assertEqual(select_timed_rates([{**base,'eta':'若干天'}]),[])
def test_english_comparison_keeps_numbers_and_renders_both_speeds(self):
text=self.ask('1000kg to USA by sea, fastest and slowest prices please')
self.assertIn('Fastest reference options',text)
self.assertIn('Slowest reference options',text)
self.assertIn('1000KG = 4000 CNY',text)
def test_different_regional_times_are_rendered_on_their_own_price_lines(self):
with self.app.app_context():
connection=db.connect()
connection.execute("UPDATE quote_rates SET eta='船开后18天左右' WHERE service='美森正班海派' AND zone='美东'")
connection.commit();connection.close()
text=self.ask('美国1000KG海运最快价格,义乌')
self.assertIn('美东 10元/KG,1000KG = 10000元(船开后18天左右提取)',text)
self.assertIn('美西 8元/KG,1000KG = 8000元',text)
def test_unknown_times_do_not_become_a_fastest_or_slowest_promise(self):
with self.app.app_context():
connection=db.connect()
connection.execute("UPDATE quote_rates SET eta='若干天'")
connection.commit();connection.close()
text=self.ask('美国1000KG海运最快和最慢价格')
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)