104 lines
4.6 KiB
Python
104 lines
4.6 KiB
Python
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.")
|