Files
baiyue-logistics-chat/logistics_chat/order_listing.py
T

70 lines
4.2 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.
"""Bounded conversational pagination over the server-validated customer scope."""
import re
import sqlite3
from .db import connect
def page_command(message):
text=re.sub(r'[\s,,。.!!??]','',message)
match=re.fullmatch(r'(?:请)?(?:订单)?第(\d{1,5})页',text)
if match:return int(match.group(1))
if re.fullmatch(r'(?:请|继续)?(?:下一页|下页|继续显示|接着显示(?:剩下的)?订单)',text):return 'next'
if re.fullmatch(r'(?:请)?(?:上一页|上页)',text):return 'previous'
return None
def answer_list(message,tenants,conv_id=None):
from .order_data import is_lookup_help,parse_count_query,tenant_filter,STATUS_LABELS
from .customer_service import order_login_response
command=page_command(message)
initial=(not is_lookup_help(message) and re.search(r'订单|运单|\borders?\b|\bshipments?\b',message,re.I)
and re.search(r'列出|列表|全部|所有|\blist\b',message,re.I))
if command is None and not initial:return None
if not tenants:return order_login_response()
page=1;status=None
if command is None:
intent=parse_count_query(re.sub(r'列出|列表|全部|所有|\blist\b','多少',message,flags=re.I))
if intent is None or intent['unsupported']:
return {'t':'暂不支持按这个条件列出订单。可查看全部订单或按履约中、已完成等业务状态查询。'}
status=intent['status']
scope=tenant_filter(tenant_ids=tenants)
if scope is None:return order_login_response()
connection=None
try:
connection=connect()
if command is not None:
if not conv_id:return {'t':'请先在当前对话中发送“列出我的订单”,再翻页查看。'}
prior=connection.execute("SELECT content FROM messages WHERE conv_id=? AND role='assistant' ORDER BY id DESC LIMIT 1",(conv_id,)).fetchone()
header=prior[0].split('\n',1)[0] if prior else ''
match=re.fullmatch(r'您当前的订单列表(.*第(\d+)页;业务状态:([^)]+)):',header)
if not match:return {'t':'请先在当前对话中发送“列出我的订单”,再翻页查看。'}
labels={label:code for code,label in STATUS_LABELS.items()}
status=labels.get(match[2])
if match[2]!='全部' and status is None:return {'t':'请重新指定需要查看的订单状态。'}
page=int(command) if isinstance(command,int) else max(1,int(match[1])+(1 if command=='next' else -1))
if not 1<=page<=10000:return {'t':'请提供1至10000之间的有效页码。'}
where=' WHERE 1=1'+scope[0];values=scope[1]
if status:where+=' AND status=?';values=values+[status]
# Both reads see one current snapshot and apply exactly the same scope/filter.
connection.execute('BEGIN')
total=connection.execute('SELECT COUNT(*) FROM order_test_data'+where,values).fetchone()[0]
page=min(page,max(1,(total+19)//20))
rows=connection.execute('SELECT order_no,inbound_code,status,warehouse_code FROM order_test_data'+where+
' ORDER BY id DESC LIMIT 20 OFFSET ?',values+[(page-1)*20]).fetchall()
if not rows:return {'t':'当前账号下没有符合条件的订单。','_customer_data':True}
label=STATUS_LABELS[status] if status else '全部'
first='先列出20票;' if page==1 and total>20 else ''
lines=[f'您当前的订单列表({first}第{page}页;业务状态:{label}):',f'共{total}票,当前显示第{(page-1)*20+1}至{(page-1)*20+len(rows)}票。']
for number,inbound,business_status,warehouse in rows:
lines.append(f'- 入仓码:{inbound or "未登记"};订单号:{number};业务状态:{STATUS_LABELS.get(business_status,business_status)};目的仓:{warehouse or "未登记"}')
lines.append('回复“下一页”查看后续订单。' if page*20<total else '当前已是最后一页。')
lines.append('发送入仓码可查询该票订单和物流轨迹。')
return {'t':'\n'.join(lines),'_customer_data':True}
except sqlite3.Error:
return {'t':'订单信息暂时无法读取,请稍后重试。'}
finally:
if connection is not None:connection.close()