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

68 lines
3.3 KiB
Python

"""Commit one model reply and its candidate state together, under ownership."""
import json
from .db import connect, make_title, now_str
def latest_message_id(conv_id):
if not conv_id:
return 0
connection = connect()
try:
return connection.execute('SELECT COALESCE(MAX(id),0) FROM messages WHERE conv_id=?', (conv_id,)).fetchone()[0]
finally:
connection.close()
def save_exchange(conv_id, question, answer, *, previous_message_id, quote_turn=None, list_state=None,
request_id=None, payload=None):
"""Return a message ID or a failure marker; never leave a partial exchange."""
if not conv_id:
return None
from flask import has_request_context
from .customer_service import attach_customer, current_customer_id, current_scope_key
from .visitor_service import visitor_id
from .conversation_state import commit_state
connection = connect()
try:
connection.execute('BEGIN IMMEDIATE')
if has_request_context():
# The write lock keeps session revocation from racing this commit.
attach_customer()
row = connection.execute('SELECT title FROM chat_history WHERE id=? AND visitor_id=? '
'AND (customer_id IS NULL OR (customer_id=? AND customer_scope=?))',
(conv_id, visitor_id(), current_customer_id(), current_scope_key())).fetchone()
if row is None:
return 'deleted'
from .chat_requests import existing_result, remember_result
cached = existing_result(connection, conv_id, request_id, question)
if cached is not None:
return cached
latest = connection.execute('SELECT id,role,content FROM messages WHERE conv_id=? ORDER BY id DESC LIMIT 1',
(conv_id,)).fetchone()
if (latest[0] if latest else 0) != previous_message_id:
return 'stale'
stamp = now_str()
if not (latest and latest[1] == 'user' and latest[2] == question):
connection.execute('INSERT INTO messages(conv_id,role,content,ctime) VALUES (?,?,?,?)',
(conv_id, 'user', question, stamp))
cursor = connection.execute('INSERT INTO messages(conv_id,role,content,ctime) VALUES (?,?,?,?)',
(conv_id, 'assistant', answer, stamp))
message_id = cursor.lastrowid
if quote_turn is not None and quote_turn.candidate is not None:
if not commit_state(connection, conv_id, quote_turn.candidate, quote_turn.expected_version):
return 'stale'
connection.execute('UPDATE chat_history SET utime=?,title=? WHERE id=?',
(stamp, make_title(question) if not row[0] or row[0] == '新对话' else row[0], conv_id))
if list_state is not None:
state = {**list_state, 'message_id': message_id}
connection.execute('UPDATE chat_history SET order_list_state=? WHERE id=? AND customer_id=? AND customer_scope=?',
(json.dumps(state, ensure_ascii=False), conv_id, current_customer_id(), current_scope_key()))
remember_result(connection, conv_id, request_id, question, payload, message_id, quote_turn)
connection.commit()
return message_id
finally:
connection.close()