Files
lc_stylist_agent/app/api/chat_router.py
pangkaicheng 4c0d8817e3 first commit
2025-10-16 14:04:42 +08:00

104 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.")