Download app/api/chat.py from umar-30/AI-todo: direct link, hf CLI and curl.
- Browser
- Download file 5.9 kB
-
https://huggingface.co/spaces/umar-30/AI-todo/resolve/main/app/api/chat.py
- Command line
-
hf download hf://spaces/umar-30/AI-todo/app/api/chat.py
-
curl -L -o chat.py https://huggingface.co/spaces/umar-30/AI-todo/resolve/main/app/api/chat.py
5.9 kB
| """ | |
| Chat API endpoint for Todo AI Chatbot. | |
| Implements POST /api/{user_id}/chat for stateless chat interactions. | |
| """ | |
| import logging | |
| from typing import Any | |
| from uuid import UUID | |
| from fastapi import APIRouter, HTTPException, Path | |
| from .schemas import ChatRequest, ChatResponse, ToolCallInfo | |
| from .services import ( | |
| ConversationAccessDeniedError, | |
| ConversationNotFoundError, | |
| create_conversation, | |
| create_message, | |
| get_conversation_with_messages, | |
| ) | |
| from ..agent import create_task_agent | |
| logger = logging.getLogger(__name__) | |
| router = APIRouter(prefix="/api", tags=["Chat"]) | |
| async def chat( | |
| request: ChatRequest, | |
| user_id: str = Path(..., min_length=1, description="User's unique identifier"), | |
| ) -> ChatResponse: | |
| """ | |
| Process a chat message and return the AI assistant's response. | |
| Creates a new conversation if conversation_id is not provided. | |
| Continues an existing conversation if conversation_id is provided. | |
| """ | |
| logger.info(f"Chat request from user {user_id}") | |
| # Validate message is not empty (after trimming) | |
| message_content = request.message.strip() | |
| if not message_content: | |
| logger.warning(f"Empty message from user {user_id}") | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Message content is required", | |
| ) | |
| try: | |
| # Load existing conversation or create new one | |
| conversation_id: UUID | |
| message_history: list[dict[str, str]] = [] | |
| if request.conversation_id: | |
| # Continue existing conversation | |
| logger.info(f"Loading conversation {request.conversation_id}") | |
| try: | |
| conversation, messages = get_conversation_with_messages( | |
| request.conversation_id, | |
| user_id, | |
| ) | |
| conversation_id = conversation.id | |
| # Build message history for agent context | |
| for msg in messages: | |
| message_history.append({ | |
| "role": msg.role, | |
| "content": msg.content, | |
| }) | |
| logger.info(f"Loaded {len(messages)} messages from conversation") | |
| except ConversationNotFoundError: | |
| logger.warning(f"Conversation {request.conversation_id} not found") | |
| raise HTTPException( | |
| status_code=404, | |
| detail="Conversation not found", | |
| ) | |
| except ConversationAccessDeniedError: | |
| logger.warning( | |
| f"User {user_id} denied access to conversation {request.conversation_id}" | |
| ) | |
| raise HTTPException( | |
| status_code=403, | |
| detail="Access denied to conversation", | |
| ) | |
| else: | |
| # Create new conversation | |
| logger.info(f"Creating new conversation for user {user_id}") | |
| conversation = create_conversation(user_id) | |
| conversation_id = conversation.id | |
| logger.info(f"Created conversation {conversation_id}") | |
| # Store user message before processing | |
| create_message( | |
| user_id=user_id, | |
| conversation_id=conversation_id, | |
| role="user", | |
| content=message_content, | |
| ) | |
| logger.info("Stored user message") | |
| # Run the AI agent with message history context | |
| agent = create_task_agent() | |
| tool_calls: list[ToolCallInfo] = [] | |
| try: | |
| # Build context with conversation history | |
| context = { | |
| "conversation_history": message_history, | |
| } | |
| # Execute agent - returns dict with response and tool_calls | |
| agent_result = await agent.run( | |
| message=message_content, | |
| user_id=user_id, | |
| context=context, | |
| ) | |
| # Extract response and tool calls from agent result | |
| response_text = agent_result.get("response", "") | |
| raw_tool_calls = agent_result.get("tool_calls", []) | |
| # Convert tool calls to ToolCallInfo objects | |
| for tc in raw_tool_calls: | |
| tool_calls.append(ToolCallInfo( | |
| name=tc.get("name", "unknown"), | |
| arguments=tc.get("arguments", {}), | |
| result=tc.get("result"), | |
| )) | |
| logger.info(f"Agent response received, {len(tool_calls)} tool calls") | |
| except Exception as e: | |
| logger.error(f"Agent processing error: {e}") | |
| raise HTTPException( | |
| status_code=500, | |
| detail="Failed to process message", | |
| ) | |
| # Store assistant response | |
| create_message( | |
| user_id=user_id, | |
| conversation_id=conversation_id, | |
| role="assistant", | |
| content=response_text, | |
| ) | |
| logger.info("Stored assistant response") | |
| return ChatResponse( | |
| conversation_id=conversation_id, | |
| response=response_text, | |
| tool_calls=tool_calls, | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| logger.error(f"Unexpected error in chat endpoint: {e}") | |
| raise HTTPException( | |
| status_code=500, | |
| detail="Failed to process message", | |
| ) | |