ishaq101's picture
[KM-467] [DED][AI] Orchestration Agent - Init
027123c
"""Room management API endpoints."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from src.db.postgres.connection import get_db
from src.db.postgres.models import Room, ChatMessage, MessageSource
from src.middlewares.logging import get_logger, log_execution
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
import uuid
logger = get_logger("room_api")
router = APIRouter(prefix="/api/v1", tags=["Rooms"])
class MessageSourceResponse(BaseModel):
document_id: Optional[str]
filename: Optional[str]
page_label: Optional[str]
class ChatMessageResponse(BaseModel):
id: str
role: str
content: str
created_at: str
sources: List[MessageSourceResponse] = []
class RoomResponse(BaseModel):
id: str
title: str
created_at: str
updated_at: str | None
messages: List[ChatMessageResponse] = []
class CreateRoomRequest(BaseModel):
user_id: str
title: str = "New Chat"
@router.get("/rooms/{user_id}", response_model=List[RoomResponse])
@log_execution(logger)
async def list_rooms(
user_id: str,
db: AsyncSession = Depends(get_db)
):
"""List all rooms for a user."""
result = await db.execute(
select(Room)
.where(Room.user_id == user_id, Room.status == "active")
.order_by(Room.updated_at.desc())
)
rooms = result.scalars().all()
return [
RoomResponse(
id=room.id,
title=room.title,
created_at=room.created_at.isoformat(),
updated_at=room.updated_at.isoformat() if room.updated_at else None
)
for room in rooms
]
@router.get("/room/{room_id}", response_model=RoomResponse)
@log_execution(logger)
async def get_room(
room_id: str,
db: AsyncSession = Depends(get_db)
):
"""Get a specific room with its chat history."""
result = await db.execute(
select(Room)
.where(Room.id == room_id)
.options(selectinload(Room.messages).selectinload(ChatMessage.sources))
)
room = result.scalars().first()
if not room:
raise HTTPException(
status_code=404,
detail="Room not found"
)
messages = sorted(room.messages, key=lambda m: m.created_at)
return RoomResponse(
id=room.id,
title=room.title,
created_at=room.created_at.isoformat(),
updated_at=room.updated_at.isoformat() if room.updated_at else None,
messages=[
ChatMessageResponse(
id=msg.id,
role=msg.role,
content=msg.content,
created_at=msg.created_at.isoformat(),
sources=[
MessageSourceResponse(
document_id=src.document_id,
filename=src.filename,
page_label=src.page_label,
)
for src in msg.sources
],
)
for msg in messages
]
)
@router.delete("/room/{room_id}")
@log_execution(logger)
async def delete_room(
room_id: str,
user_id: str,
db: AsyncSession = Depends(get_db)
):
"""Soft-delete a room by setting its status to inactive."""
result = await db.execute(
select(Room).where(Room.id == room_id)
)
room = result.scalars().first()
if not room:
raise HTTPException(status_code=404, detail="Room not found")
if room.user_id != user_id:
raise HTTPException(status_code=403, detail="Access denied")
room.status = "inactive"
await db.commit()
return {"status": "success", "message": "Room deleted successfully"}
@router.post("/room/create")
@log_execution(logger)
async def create_room(
request: CreateRoomRequest,
db: AsyncSession = Depends(get_db)
):
"""Create a new room."""
room = Room(
id=str(uuid.uuid4()),
user_id=request.user_id,
title=request.title
)
db.add(room)
await db.commit()
await db.refresh(room)
return {
"status": "success",
"message": "Room created successfully",
"data": RoomResponse(
id=room.id,
title=room.title,
created_at=room.created_at.isoformat(),
updated_at=None
)
}