Files
aiagent/saars/backend/app/api/chat.py
2026-03-07 09:01:00 +08:00

88 lines
3.2 KiB
Python

"""
Chat REST API: conversations, messages, recall.
"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from app.services.chat_engine import ChatEngineService
from app.socket_events import broadcast_new_message
chat_bp = Blueprint("chat", __name__)
@chat_bp.route("/conversations", methods=["GET"])
@jwt_required()
def list_conversations():
skip = request.args.get("skip", 0, type=int)
limit = min(request.args.get("limit", 20, type=int), 100)
user_id = get_jwt_identity()
convs = ChatEngineService.list_conversations(user_id, skip=skip, limit=limit)
return jsonify({
"items": [
{
"id": c.id,
"title": c.title,
"last_message_at": c.last_message_at.isoformat() if c.last_message_at else None,
"created_at": c.created_at.isoformat() if c.created_at else None,
}
for c in convs
]
})
@chat_bp.route("/conversations", methods=["POST"])
@jwt_required()
def create_conversation():
data = request.get_json() or {}
title = (data.get("title") or "新对话").strip() or "新对话"
user_id = get_jwt_identity()
conv = ChatEngineService.get_or_create_conversation(user_id, title=title)
return jsonify({
"id": conv.id,
"title": conv.title,
"last_message_at": conv.last_message_at.isoformat() if conv.last_message_at else None,
"created_at": conv.created_at.isoformat() if conv.created_at else None,
}), 201
@chat_bp.route("/conversations/<conversation_id>/messages", methods=["GET"])
@jwt_required()
def get_messages(conversation_id):
before_id = request.args.get("before_id")
limit = min(request.args.get("limit", 50, type=int), 100)
user_id = get_jwt_identity()
messages = ChatEngineService.get_messages(conversation_id, user_id, before_id=before_id, limit=limit)
return jsonify({"items": [m.to_dict() for m in reversed(messages)]})
@chat_bp.route("/conversations/<conversation_id>/messages", methods=["POST"])
@jwt_required()
def send_message(conversation_id):
data = request.get_json() or {}
content = (data.get("content") or "").strip()
content_type = data.get("content_type") or "text"
attachment_url = data.get("attachment_url")
attachment_name = data.get("attachment_name")
if not content and not attachment_url:
return jsonify({"error": "content or attachment required"}), 400
user_id = get_jwt_identity()
msg = ChatEngineService.send_message(
conversation_id, user_id, content or "(附件)",
content_type=content_type,
attachment_url=attachment_url,
attachment_name=attachment_name,
)
if not msg:
return jsonify({"error": "Conversation not found or access denied"}), 404
broadcast_new_message(msg)
return jsonify(msg.to_dict()), 201
@chat_bp.route("/messages/<message_id>/recall", methods=["POST"])
@jwt_required()
def recall_message(message_id):
user_id = get_jwt_identity()
ok = ChatEngineService.recall_message(message_id, user_id)
if not ok:
return jsonify({"error": "Message not found or recall not allowed"}), 400
return jsonify({"status": "recalled"})