82 lines
3.5 KiB
Python
82 lines
3.5 KiB
Python
"""Replay committed chat operations under the current conversation identity."""
|
|
|
|
import hashlib
|
|
import json
|
|
|
|
|
|
def init_request_schema(connection):
|
|
connection.execute('''CREATE TABLE IF NOT EXISTS chat_request_results (
|
|
conv_id INTEGER NOT NULL, request_id TEXT NOT NULL, identity TEXT NOT NULL,
|
|
question TEXT NOT NULL, payload TEXT NOT NULL, message_id INTEGER NOT NULL,
|
|
quote_state TEXT, PRIMARY KEY(conv_id, request_id, identity))''')
|
|
connection.execute('''CREATE TRIGGER IF NOT EXISTS delete_chat_request_results
|
|
AFTER DELETE ON chat_history BEGIN
|
|
DELETE FROM chat_request_results WHERE conv_id=OLD.id;
|
|
END''')
|
|
|
|
|
|
def identity_key():
|
|
from .customer_service import current_customer_id, current_scope_key
|
|
from .visitor_service import visitor_id
|
|
return hashlib.sha256(json.dumps([visitor_id(), current_customer_id(), current_scope_key()]).encode()).hexdigest()
|
|
|
|
|
|
def existing_result(connection, conv_id, request_id, question):
|
|
if not request_id or not conv_id:
|
|
return None
|
|
row = connection.execute('SELECT question,payload,quote_state FROM chat_request_results '
|
|
'WHERE conv_id=? AND request_id=? AND identity=?', (conv_id, request_id, identity_key())).fetchone()
|
|
if row is None:
|
|
return None
|
|
if row[0] != question:
|
|
raise ValueError('请求标识已用于其他问题,请重新发送。')
|
|
if row[2]:
|
|
state = json.loads(row[2])
|
|
book = connection.execute('SELECT id FROM quote_books WHERE active=1 ORDER BY id DESC LIMIT 1').fetchone()
|
|
if state.get('book_id') != (book[0] if book else None):
|
|
raise ValueError('报价资料已更新,请按当前货物条件重新询价。')
|
|
return json.loads(row[1])
|
|
|
|
|
|
def replay_result(conv_id, request_id, question):
|
|
from .db import connect
|
|
from .visitor_service import owns_conversation
|
|
if not request_id or not conv_id or not owns_conversation(conv_id):
|
|
return None
|
|
connection = connect()
|
|
try:
|
|
return existing_result(connection, conv_id, request_id, question)
|
|
finally:
|
|
connection.close()
|
|
|
|
|
|
def login_quote_replay(conv_id, request_id, question):
|
|
"""Login may refresh orders while the original public quote edit stays applied."""
|
|
from .customer_service import current_customer_id
|
|
from .db import connect
|
|
from .visitor_service import owns_conversation
|
|
if not request_id or not current_customer_id() or not owns_conversation(conv_id):
|
|
return None
|
|
connection = connect()
|
|
try:
|
|
rows = connection.execute('SELECT payload,quote_state FROM chat_request_results '
|
|
'WHERE conv_id=? AND request_id=? AND question=? AND quote_state IS NOT NULL',
|
|
(conv_id, request_id, question))
|
|
for payload, state in rows:
|
|
if json.loads(payload).get('login_required'):
|
|
return json.loads(state)
|
|
return None
|
|
finally:
|
|
connection.close()
|
|
|
|
|
|
def remember_result(connection, conv_id, request_id, question, payload, message_id, quote_turn):
|
|
if not request_id:
|
|
return
|
|
if not isinstance(payload, dict):
|
|
raise ValueError('A completed response is required')
|
|
state = (quote_turn.candidate or getattr(quote_turn, 'replay_state', None)) if quote_turn else None
|
|
connection.execute('INSERT INTO chat_request_results VALUES(?,?,?,?,?,?,?)',
|
|
(conv_id, request_id, identity_key(), question, json.dumps(payload, ensure_ascii=False), message_id,
|
|
json.dumps(state, ensure_ascii=False) if state else None))
|