from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from typing import List, Dict # 导入 ChatbotAgent 类和配置 # 假设 ChatbotAgent 是单例或在应用启动时创建 from app.core.chatbot_agent import ChatbotAgent from app.core.config import settings # --- Pydantic Data Models --- # 用于接收用户消息的请求体 class ChatRequest(BaseModel): user_id: str = Field(..., description="Unique identifier for the user.") user_message: str = Field(..., description="The user's text message.") # 用于启动搭配推荐的请求体 class OutfitStartRequest(BaseModel): user_id: str = Field(..., description="Unique identifier for the user.") stylist_name: str = Field("crystal", description="The name of the stylist guide to use (e.g., 'crystal').") # 用于从已选单品继续搭配,可选 start_outfit: List[Dict[str, str]] = Field(default_factory=list, description="Optional list of items already selected.") # 用于返回 LLM/Agent 的文本回复 class ChatResponse(BaseModel): response_text: str = Field(..., description="The chatbot's text response.") # 搭配推荐的响应体 (StylistAgent的输出是JSON,这里简化为字符串,实际项目中会返回结构化的JSON) class OutfitResponse(BaseModel): summary: str = Field(..., description="The conversation summary used for styling.") next_item_json: Dict = Field(..., description="The next recommended item in JSON format.") # --- Router Setup --- router = APIRouter( prefix="/chat", tags=["Chatbot & Styling"] ) # 在应用启动时实例化 ChatbotAgent,以便在路由中使用同一个实例 # 注意:在真实的 FastAPI 应用中,我们通常使用依赖注入 (Depends) 来管理实例 try: # 假设 ChatbotAgent 的 __init__ 已经包含了所有依赖的初始化 global_agent = ChatbotAgent() except Exception as e: # 如果依赖(如 Redis 或 VectorDB)初始化失败,抛出错误 print(f"FATAL: ChatbotAgent failed to initialize. Error: {e}") global_agent = None # 保持 None 状态,路由会抛出 500 @router.post("/", response_model=ChatResponse, summary="Process user message and get chatbot response") def handle_chat_message(request: ChatRequest): """ 处理用户的聊天消息,将消息添加到历史记录,并调用 LLM 生成回复。 """ if not global_agent: raise HTTPException(status_code=500, detail="Chatbot agent not initialized.") try: response = global_agent.process_query(request.user_id, request.user_message) return ChatResponse(response_text=response) except Exception as e: print(f"Error processing chat query: {e}") # 返回一个通用错误信息,而不是内部错误 raise HTTPException(status_code=500, detail="Internal server error while processing message.") @router.post("/outfit/start", summary="Start outfit recommendation based on conversation history") def start_outfit_recommendation(request: OutfitStartRequest): """ 基于用户的对话历史,生成搭配总结,并启动 Stylist Agent 推荐第一个单品。 返回:对话总结和 Stylist Agent 推荐的第一个单品的 JSON。 """ if not global_agent: raise HTTPException(status_code=500, detail="Chatbot agent not initialized.") try: # 1. 获取对话总结 request_summary = global_agent.get_conversation_summary(request.user_id) # 2. 调用 Stylist Agent 运行搭配流程 # run_styling_process 应该返回 Stylist Agent 的第一个 JSON 输出 (recommend_item) # 假设 StylistAgent.run_styling_process 返回一个 JSON 字典 next_item_json = global_agent.stylist_agent.run_styling_process( request_summary, request.stylist_name, request.start_outfit ) return OutfitResponse( summary=request_summary, next_item_json=next_item_json ) except Exception as e: print(f"Error starting outfit recommendation: {e}") raise HTTPException(status_code=500, detail=f"Failed to start styling process: {e}") # (可选) 搭配继续接口:用于处理用户的反馈和继续推荐 @router.post("/outfit/continue", summary="Continue outfit recommendation with user feedback") def continue_outfit_recommendation(): """ 这是一个占位符,用于处理用户对已推荐单品(如图片)的反馈,并让 Stylist Agent 推荐下一个单品。 """ raise HTTPException(status_code=501, detail="Endpoint for outfit continuation is not yet implemented.")