79 lines
2.7 KiB
Python
79 lines
2.7 KiB
Python
"""Chat engine: message persistence, status tracking, recall."""
|
|
from datetime import datetime
|
|
from app import db
|
|
from app.models.chat import Conversation, Message, MessageStatus
|
|
|
|
|
|
class ChatEngineService:
|
|
@staticmethod
|
|
def get_or_create_conversation(user_id, title="新对话"):
|
|
conv = Conversation.query.filter_by(user_id=user_id).order_by(
|
|
Conversation.last_message_at.desc()
|
|
).first()
|
|
if conv:
|
|
return conv
|
|
conv = Conversation(user_id=user_id, title=title)
|
|
db.session.add(conv)
|
|
db.session.commit()
|
|
return conv
|
|
|
|
@staticmethod
|
|
def list_conversations(user_id, skip=0, limit=20):
|
|
return Conversation.query.filter_by(user_id=user_id).order_by(
|
|
Conversation.last_message_at.desc()
|
|
).offset(skip).limit(limit).all()
|
|
|
|
@staticmethod
|
|
def send_message(conversation_id, sender_id, content, content_type="text",
|
|
attachment_url=None, attachment_name=None):
|
|
conv = Conversation.query.get(conversation_id)
|
|
if not conv or str(conv.user_id) != str(sender_id):
|
|
return None
|
|
msg = Message(
|
|
conversation_id=conversation_id,
|
|
sender_id=sender_id,
|
|
content=content,
|
|
content_type=content_type or "text",
|
|
attachment_url=attachment_url,
|
|
attachment_name=attachment_name,
|
|
status=MessageStatus.SENT,
|
|
)
|
|
db.session.add(msg)
|
|
conv.last_message_at = datetime.utcnow()
|
|
db.session.commit()
|
|
return msg
|
|
|
|
@staticmethod
|
|
def get_messages(conversation_id, user_id, before_id=None, limit=50):
|
|
conv = Conversation.query.get(conversation_id)
|
|
if not conv or str(conv.user_id) != str(user_id):
|
|
return []
|
|
q = Message.query.filter_by(conversation_id=conversation_id).filter(
|
|
Message.is_recalled == False
|
|
)
|
|
if before_id:
|
|
before = Message.query.get(before_id)
|
|
if before:
|
|
q = q.filter(Message.created_at < before.created_at)
|
|
return q.order_by(Message.created_at.desc()).limit(limit).all()
|
|
|
|
@staticmethod
|
|
def recall_message(message_id, user_id):
|
|
msg = Message.query.get(message_id)
|
|
if not msg or str(msg.sender_id) != str(user_id):
|
|
return False
|
|
msg.is_recalled = True
|
|
msg.recalled_at = datetime.utcnow()
|
|
msg.status = MessageStatus.RECALLED
|
|
db.session.commit()
|
|
return True
|
|
|
|
@staticmethod
|
|
def update_message_status(message_id, status):
|
|
msg = Message.query.get(message_id)
|
|
if not msg:
|
|
return False
|
|
msg.status = status
|
|
db.session.commit()
|
|
return True
|