1+ # Placeholder for conversation management routes
2+
3+ import uuid
4+ from typing import Any
5+
6+ from fastapi import APIRouter , HTTPException , Depends
7+ from sqlmodel import Session
8+
9+ from app .api .deps import SessionDep , CurrentUser
10+ from app import crud
11+ from app .models import (
12+ Conversation , ConversationCreate , ConversationPublic , ConversationsPublic ,
13+ Message , MessageCreate , MessagePublic , MessagesPublic , MessageSender ,
14+ CharacterStatus , Character # Import Character
15+ )
16+ # Import AI service
17+ from app .services import ai_service
18+
19+ router = APIRouter (prefix = "/conversations" , tags = ["conversations" ])
20+
21+
22+ @router .post ("/" , response_model = ConversationPublic , status_code = 201 )
23+ def start_conversation (
24+ * , session : SessionDep , current_user : CurrentUser , conversation_in : ConversationCreate
25+ ) -> Any :
26+ """
27+ Start a new conversation with an approved character.
28+ """
29+ # Check if character exists and is approved
30+ character = crud .characters .get_character (
31+ session = session , character_id = conversation_in .character_id
32+ )
33+ if not character or character .status != CharacterStatus .APPROVED :
34+ raise HTTPException (status_code = 404 , detail = "Approved character not found" )
35+
36+ try :
37+ conversation = crud .conversations .create_conversation (
38+ session = session , conversation_create = conversation_in , user_id = current_user .id
39+ )
40+ except ValueError as e :
41+ # Catch potential errors from CRUD (like character not found again, just in case)
42+ raise HTTPException (status_code = 404 , detail = str (e ))
43+
44+ # Optionally: Add the character's greeting message as the first AI message
45+ if character .greeting_message :
46+ crud .conversations .create_message (
47+ session = session ,
48+ message_create = MessageCreate (content = character .greeting_message ),
49+ conversation_id = conversation .id ,
50+ sender = MessageSender .AI
51+ )
52+ session .refresh (conversation ) # Refresh to potentially load the new message relationship
53+
54+ return conversation
55+
56+
57+ @router .get ("/" , response_model = ConversationsPublic )
58+ def list_my_conversations (
59+ session : SessionDep , current_user : CurrentUser , skip : int = 0 , limit : int = 100
60+ ) -> Any :
61+ """
62+ Retrieve conversations for the current user.
63+ """
64+ count = crud .conversations .get_user_conversations_count (
65+ session = session , user_id = current_user .id
66+ )
67+ conversations = crud .conversations .get_user_conversations (
68+ session = session , user_id = current_user .id , skip = skip , limit = limit
69+ )
70+ return ConversationsPublic (data = conversations , count = count )
71+
72+
73+ @router .get ("/{conversation_id}/messages" , response_model = MessagesPublic )
74+ def get_conversation_messages_route (
75+ session : SessionDep , current_user : CurrentUser , conversation_id : uuid .UUID , skip : int = 0 , limit : int = 100
76+ ) -> Any :
77+ """
78+ Retrieve messages for a specific conversation owned by the current user.
79+ """
80+ conversation = crud .conversations .get_conversation (
81+ session = session , conversation_id = conversation_id
82+ )
83+ if not conversation :
84+ raise HTTPException (status_code = 404 , detail = "Conversation not found" )
85+ if conversation .user_id != current_user .id :
86+ raise HTTPException (status_code = 403 , detail = "Not authorized to view these messages" )
87+
88+ count = crud .conversations .get_conversation_messages_count (
89+ session = session , conversation_id = conversation_id
90+ )
91+ messages = crud .conversations .get_conversation_messages (
92+ session = session , conversation_id = conversation_id , skip = skip , limit = limit
93+ )
94+ return MessagesPublic (data = messages , count = count )
95+
96+
97+ @router .post ("/{conversation_id}/messages" , response_model = MessagePublic )
98+ def send_message (
99+ * , session : SessionDep , current_user : CurrentUser , conversation_id : uuid .UUID , message_in : MessageCreate
100+ ) -> Any :
101+ """
102+ Send a message from the user to a conversation and get an AI response.
103+ """
104+ conversation = crud .conversations .get_conversation (
105+ session = session , conversation_id = conversation_id
106+ )
107+ if not conversation :
108+ raise HTTPException (status_code = 404 , detail = "Conversation not found" )
109+ if conversation .user_id != current_user .id :
110+ raise HTTPException (status_code = 403 , detail = "Not authorized to send messages to this conversation" )
111+ if not conversation .character : # Ensure character relationship is loaded or handle if None
112+ # This might require adjusting how conversations are fetched or created if lazy loading isn't setup
113+ # For now, assume it exists if conversation exists
114+ raise HTTPException (status_code = 500 , detail = "Character details missing for conversation" )
115+
116+ # 1. Save the user's message
117+ user_message = crud .conversations .create_message (
118+ session = session ,
119+ message_create = message_in ,
120+ conversation_id = conversation_id ,
121+ sender = MessageSender .USER
122+ )
123+
124+ # 2. Prepare context and get AI response
125+ # Get recent messages (including the one just sent by the user)
126+ # Adjust limit as needed for AI context window
127+ message_history = crud .conversations .get_conversation_messages (
128+ session = session , conversation_id = conversation_id , limit = 20
129+ )
130+
131+ ai_response_text = ai_service .get_ai_response (
132+ character = conversation .character ,
133+ history = message_history
134+ )
135+
136+ # 3. Save the AI's message
137+ ai_message = crud .conversations .create_message (
138+ session = session ,
139+ message_create = MessageCreate (content = ai_response_text ),
140+ conversation_id = conversation_id ,
141+ sender = MessageSender .AI
142+ )
143+
144+ # Return the AI's response message
145+ return ai_message
146+
147+
148+ @router .delete ("/{conversation_id}" , status_code = 204 )
149+ def delete_conversation_route (
150+ session : SessionDep , current_user : CurrentUser , conversation_id : uuid .UUID
151+ ) -> None :
152+ """
153+ Delete a conversation owned by the current user.
154+ """
155+ conversation = crud .conversations .get_conversation (
156+ session = session , conversation_id = conversation_id
157+ )
158+ if not conversation :
159+ # Idempotent delete: if not found, act as if deleted
160+ return None
161+ if conversation .user_id != current_user .id :
162+ raise HTTPException (status_code = 403 , detail = "Not authorized to delete this conversation" )
163+
164+ crud .conversations .delete_conversation (session = session , db_conversation = conversation )
165+ return None # No content response
0 commit comments