184 lines
5.7 KiB
Python
184 lines
5.7 KiB
Python
"""Chat Room API Routes"""
|
|
from typing import List, Optional
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from luxx.services.room import chat_room_service
|
|
|
|
router = APIRouter(prefix="/chat-rooms", tags=["chat-rooms"])
|
|
|
|
|
|
class CreateChatRoomRequest(BaseModel):
|
|
name: str
|
|
description: Optional[str] = None
|
|
agent_ids: Optional[List[str]] = None
|
|
|
|
|
|
class UpdateChatRoomRequest(BaseModel):
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
is_active: Optional[bool] = None
|
|
|
|
|
|
class SendMessageRequest(BaseModel):
|
|
content: str
|
|
reply_to: Optional[str] = None # Message ID to reply to
|
|
mentions: Optional[List[str]] = None # Mentioned agent IDs
|
|
|
|
|
|
class AddAgentRequest(BaseModel):
|
|
agent_id: str
|
|
|
|
|
|
def get_current_user_id() -> int:
|
|
"""Get current user ID from auth context"""
|
|
return 1
|
|
|
|
|
|
@router.get("")
|
|
async def list_chat_rooms():
|
|
"""List all chat rooms"""
|
|
user_id = get_current_user_id()
|
|
rooms = chat_room_service.list_rooms(user_id=user_id)
|
|
return {"rooms": rooms}
|
|
|
|
|
|
@router.post("")
|
|
async def create_chat_room(request: CreateChatRoomRequest):
|
|
"""Create a new chat room"""
|
|
user_id = get_current_user_id()
|
|
room = chat_room_service.create_room(
|
|
name=request.name,
|
|
owner_id=user_id,
|
|
description=request.description,
|
|
agent_ids=request.agent_ids
|
|
)
|
|
return {"room": room}
|
|
|
|
|
|
@router.get("/{room_id}")
|
|
async def get_chat_room(room_id: str):
|
|
"""Get a chat room by ID with agents"""
|
|
room = chat_room_service.get_room(room_id)
|
|
if not room:
|
|
raise HTTPException(status_code=404, detail="Chat room not found")
|
|
return {"room": room.to_dict(include_agents=True)}
|
|
|
|
|
|
@router.put("/{room_id}")
|
|
async def update_chat_room(room_id: str, request: UpdateChatRoomRequest):
|
|
"""Update a chat room"""
|
|
room = chat_room_service.update_room(
|
|
room_id=room_id,
|
|
name=request.name,
|
|
description=request.description,
|
|
is_active=request.is_active
|
|
)
|
|
if not room:
|
|
raise HTTPException(status_code=404, detail="Chat room not found")
|
|
return {"room": room}
|
|
|
|
|
|
@router.delete("/{room_id}")
|
|
async def delete_chat_room(room_id: str):
|
|
"""Delete a chat room and all related data"""
|
|
success = chat_room_service.delete_room(room_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Chat room not found")
|
|
return {"success": True}
|
|
|
|
|
|
@router.get("/{room_id}/agents")
|
|
async def get_room_agents(room_id: str):
|
|
"""Get all agents in a chat room (from stable RoomAgent table)"""
|
|
# Return both BaseAgent objects and info from RoomAgent table
|
|
agents = chat_room_service.get_room_agents(room_id)
|
|
agents_info = chat_room_service.get_room_agents_info(room_id)
|
|
|
|
# Merge agent data
|
|
agent_data = []
|
|
for agent in agents:
|
|
agent_dict = agent.to_dict()
|
|
# Find matching info
|
|
for info in agents_info:
|
|
if info.get("id") == agent.agent_id:
|
|
agent_dict.update(info)
|
|
break
|
|
agent_data.append(agent_dict)
|
|
|
|
return {"agents": agent_data, "count": len(agent_data)}
|
|
|
|
|
|
@router.post("/{room_id}/agents")
|
|
async def add_agent_to_room(room_id: str, request: AddAgentRequest):
|
|
"""Add an agent to a chat room"""
|
|
success = chat_room_service.add_agent_to_room(room_id, request.agent_id)
|
|
if not success:
|
|
raise HTTPException(status_code=400, detail="Failed to add agent")
|
|
# Return updated agents list
|
|
agents = chat_room_service.get_room_agents_info(room_id)
|
|
return {"success": True, "agents": agents}
|
|
|
|
|
|
@router.delete("/{room_id}/agents/{agent_id}")
|
|
async def remove_agent_from_room(room_id: str, agent_id: str):
|
|
"""Remove an agent from a chat room"""
|
|
success = chat_room_service.remove_agent_from_room(room_id, agent_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Agent not found in room")
|
|
return {"success": True}
|
|
|
|
|
|
@router.get("/{room_id}/messages")
|
|
async def get_room_messages(room_id: str, limit: int = 50, before_id: str = None):
|
|
"""Get messages from a chat room"""
|
|
messages = chat_room_service.get_messages(room_id, limit=limit, before_id=before_id)
|
|
return {"messages": messages, "count": len(messages)}
|
|
|
|
|
|
@router.post("/{room_id}/messages")
|
|
async def send_message(room_id: str, request: SendMessageRequest):
|
|
"""Send a message to a chat room. Returns a streaming response via SSE.
|
|
|
|
This endpoint is for HTTP-based messaging. WebSocket is preferred for real-time chat.
|
|
"""
|
|
from fastapi.responses import StreamingResponse
|
|
import json
|
|
|
|
user_id = str(get_current_user_id())
|
|
user_name = "User"
|
|
|
|
async def generate():
|
|
# Save user message first
|
|
user_msg = chat_room_service.save_message(
|
|
room_id=room_id,
|
|
sender_type="user",
|
|
sender_name=user_name,
|
|
content=request.content,
|
|
sender_id=user_id,
|
|
mentions=request.mentions,
|
|
parent_id=request.reply_to
|
|
)
|
|
|
|
# Yield saved message event
|
|
yield f"data: {json.dumps({'event': 'message', 'data': {'message': user_msg}}, ensure_ascii=False)}\n\n"
|
|
|
|
# Process and stream agent responses
|
|
async for event in chat_room_service.process_message(
|
|
room_id=room_id,
|
|
user_message=request.content,
|
|
sender_id=user_id,
|
|
sender_name=user_name
|
|
):
|
|
yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
|
|
|
|
return StreamingResponse(
|
|
generate(),
|
|
media_type="text/event-stream",
|
|
headers={
|
|
"Cache-Control": "no-cache",
|
|
"Connection": "keep-alive",
|
|
"X-Accel-Buffering": "no"
|
|
}
|
|
)
|