feat(chat): implement native hub chat with sqlite conversations store, SSE streaming and DSH 5th universe integration
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
from fastapi import APIRouter, HTTPException, Query, Body, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
from typing import Optional, Dict, Any, List
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.chat_service import (
|
||||
list_universe_conversations,
|
||||
create_universe_conversation,
|
||||
get_conversation_messages,
|
||||
stream_chat_messages,
|
||||
rename_universe_conversation,
|
||||
pin_universe_conversation,
|
||||
delete_universe_conversation
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/chat", tags=["Chat"])
|
||||
|
||||
class CreateConversationRequest(BaseModel):
|
||||
title: Optional[str] = "Nouvelle conversation"
|
||||
|
||||
class UpdateConversationRequest(BaseModel):
|
||||
title: Optional[str] = None
|
||||
pinned: Optional[bool] = None
|
||||
|
||||
class SendMessageRequest(BaseModel):
|
||||
message: str
|
||||
|
||||
@router.get("/{universe_id}/conversations")
|
||||
async def get_conversations(universe_id: str):
|
||||
"""Returns the list of conversations for a universe."""
|
||||
convs = await list_universe_conversations(universe_id)
|
||||
return {"ok": True, "universe_id": universe_id, "conversations": convs}
|
||||
|
||||
@router.post("/{universe_id}/conversations")
|
||||
async def create_conversation(universe_id: str, body: CreateConversationRequest = Body(default_factory=CreateConversationRequest)):
|
||||
"""Creates a new conversation in a universe."""
|
||||
conv = await create_universe_conversation(universe_id, title=body.title)
|
||||
return {"ok": True, "conversation": conv}
|
||||
|
||||
@router.get("/{universe_id}/conversations/{session_key}/messages")
|
||||
async def get_messages(universe_id: str, session_key: str):
|
||||
"""Retrieves full message history for a conversation."""
|
||||
messages = await get_conversation_messages(universe_id, session_key)
|
||||
return {"ok": True, "session_key": session_key, "messages": messages}
|
||||
|
||||
@router.post("/{universe_id}/conversations/{session_key}/send")
|
||||
async def send_message(universe_id: str, session_key: str, body: SendMessageRequest):
|
||||
"""Sends a message and streams SSE chunks back."""
|
||||
if not body.message or not body.message.strip():
|
||||
raise HTTPException(status_code=400, detail="Message cannot be empty")
|
||||
|
||||
stream = stream_chat_messages(universe_id, session_key, body.message.strip())
|
||||
return StreamingResponse(
|
||||
stream,
|
||||
media_type="text/event-stream",
|
||||
headers={
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
"X-Accel-Buffering": "no"
|
||||
}
|
||||
)
|
||||
|
||||
@router.patch("/{universe_id}/conversations/{session_key}")
|
||||
async def update_conv(universe_id: str, session_key: str, body: UpdateConversationRequest):
|
||||
"""Updates conversation title or pinned status."""
|
||||
if body.title is not None:
|
||||
await rename_universe_conversation(universe_id, session_key, body.title)
|
||||
if body.pinned is not None:
|
||||
await pin_universe_conversation(universe_id, session_key, body.pinned)
|
||||
return {"ok": True}
|
||||
|
||||
@router.delete("/{universe_id}/conversations/{session_key}")
|
||||
async def delete_conv(universe_id: str, session_key: str):
|
||||
"""Deletes a conversation."""
|
||||
await delete_universe_conversation(universe_id, session_key)
|
||||
return {"ok": True}
|
||||
Reference in New Issue
Block a user