chat_history.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. """
  2. 聊天历史API路由
  3. """
  4. from fastapi import APIRouter, Depends, HTTPException, status
  5. from sqlalchemy.orm import Session
  6. from pydantic import BaseModel, validator
  7. from typing import List, Optional
  8. from datetime import datetime
  9. from enum import Enum
  10. from backend.core.database import get_db
  11. from backend.core.models import User, ChatHistory, ChatMessage
  12. from backend.core.auth import get_current_user
  13. router = APIRouter(tags=["chat"], prefix="/chat-history")
  14. # 添加角色枚举类型
  15. class MessageRole(str, Enum):
  16. USER = "user"
  17. ASSISTANT = "assistant"
  18. SYSTEM = "system"
  19. class MessageCreate(BaseModel):
  20. role: MessageRole # 使用枚举类型替代字符串
  21. content: str
  22. # 添加额外验证器
  23. @validator('content')
  24. def content_must_not_be_empty(cls, v):
  25. if not v or not v.strip():
  26. raise ValueError('消息内容不能为空')
  27. return v
  28. # 添加角色验证器,尝试将字符串转换为枚举
  29. @validator('role', pre=True)
  30. def validate_role(cls, v):
  31. if isinstance(v, MessageRole):
  32. return v
  33. if isinstance(v, str):
  34. # 尝试将字符串匹配到枚举值
  35. if v.lower() == "user":
  36. return MessageRole.USER
  37. elif v.lower() == "assistant":
  38. return MessageRole.ASSISTANT
  39. elif v.lower() == "system":
  40. return MessageRole.SYSTEM
  41. # 如果无法匹配,默认返回USER
  42. return MessageRole.USER
  43. class MessageResponse(BaseModel):
  44. id: int
  45. role: str
  46. content: str
  47. timestamp: datetime
  48. class Config:
  49. orm_mode = True
  50. class ChatHistoryCreate(BaseModel):
  51. title: str
  52. messages: List[MessageCreate]
  53. class ChatHistoryResponse(BaseModel):
  54. id: int
  55. title: str
  56. created_at: datetime
  57. updated_at: datetime
  58. messages: List[MessageResponse]
  59. class Config:
  60. orm_mode = True
  61. class ChatHistorySummary(BaseModel):
  62. id: int
  63. title: str
  64. created_at: datetime
  65. updated_at: datetime
  66. class Config:
  67. orm_mode = True
  68. class ChatHistoryUpdate(BaseModel):
  69. title: Optional[str] = None
  70. @router.post("/", response_model=ChatHistoryResponse)
  71. async def create_chat_history(
  72. chat_data: ChatHistoryCreate,
  73. current_user: User = Depends(get_current_user),
  74. db: Session = Depends(get_db)
  75. ):
  76. """创建新的聊天历史"""
  77. try:
  78. # 打印接收到的数据
  79. print("收到的聊天历史数据:", chat_data)
  80. # 创建聊天历史
  81. chat = ChatHistory(
  82. user_id=current_user.id,
  83. title=chat_data.title
  84. )
  85. db.add(chat)
  86. db.commit()
  87. db.refresh(chat)
  88. # 添加消息
  89. for msg_data in chat_data.messages:
  90. message = ChatMessage(
  91. chat_id=chat.id,
  92. role=msg_data.role,
  93. content=msg_data.content
  94. )
  95. db.add(message)
  96. db.commit()
  97. db.refresh(chat)
  98. return chat
  99. except Exception as e:
  100. # 打印详细错误信息
  101. print("保存聊天历史出错:", str(e))
  102. raise
  103. @router.get("/", response_model=List[ChatHistorySummary])
  104. async def get_chat_histories(
  105. current_user: User = Depends(get_current_user),
  106. db: Session = Depends(get_db)
  107. ):
  108. """获取用户的所有聊天历史摘要"""
  109. # 获取基本聊天历史记录
  110. chats_query = db.query(ChatHistory)\
  111. .filter(ChatHistory.user_id == current_user.id)\
  112. .order_by(ChatHistory.updated_at.desc())
  113. chats = chats_query.all()
  114. # 增强聊天记录信息
  115. for chat in chats:
  116. # 获取消息数量
  117. message_count = db.query(ChatMessage)\
  118. .filter(ChatMessage.chat_id == chat.id)\
  119. .count()
  120. chat.message_count = message_count
  121. # 获取最新的用户消息作为预览
  122. last_user_message = db.query(ChatMessage)\
  123. .filter(ChatMessage.chat_id == chat.id, ChatMessage.role == "user")\
  124. .order_by(ChatMessage.timestamp.desc())\
  125. .first()
  126. if last_user_message:
  127. # 截取前100个字符作为预览
  128. preview = last_user_message.content[:100]
  129. if len(last_user_message.content) > 100:
  130. preview += "..."
  131. chat.preview = preview
  132. else:
  133. chat.preview = ""
  134. # 检查是否包含代码
  135. has_code = db.query(ChatMessage)\
  136. .filter(
  137. ChatMessage.chat_id == chat.id,
  138. ChatMessage.content.like("%```%")
  139. ).count() > 0
  140. chat.has_code = has_code
  141. return chats
  142. @router.get("/{chat_id}", response_model=ChatHistoryResponse)
  143. async def get_chat_history(
  144. chat_id: int,
  145. current_user: User = Depends(get_current_user),
  146. db: Session = Depends(get_db)
  147. ):
  148. """获取特定聊天历史的详情"""
  149. chat = db.query(ChatHistory)\
  150. .filter(ChatHistory.id == chat_id, ChatHistory.user_id == current_user.id)\
  151. .first()
  152. if not chat:
  153. raise HTTPException(
  154. status_code=status.HTTP_404_NOT_FOUND,
  155. detail="聊天历史不存在或无权访问"
  156. )
  157. return chat
  158. @router.post("/{chat_id}/messages", response_model=MessageResponse)
  159. async def add_message(
  160. chat_id: int,
  161. message: MessageCreate,
  162. current_user: User = Depends(get_current_user),
  163. db: Session = Depends(get_db)
  164. ):
  165. """向现有聊天添加新消息"""
  166. # 检查聊天是否存在且属于当前用户
  167. chat = db.query(ChatHistory)\
  168. .filter(ChatHistory.id == chat_id, ChatHistory.user_id == current_user.id)\
  169. .first()
  170. if not chat:
  171. raise HTTPException(
  172. status_code=status.HTTP_404_NOT_FOUND,
  173. detail="聊天历史不存在或无权访问"
  174. )
  175. # 创建新消息
  176. db_message = ChatMessage(
  177. chat_id=chat_id,
  178. role=message.role,
  179. content=message.content
  180. )
  181. # 更新聊天的更新时间
  182. chat.updated_at = datetime.utcnow()
  183. db.add(db_message)
  184. db.commit()
  185. db.refresh(db_message)
  186. return db_message
  187. @router.delete("/{chat_id}")
  188. async def delete_chat_history(
  189. chat_id: int,
  190. current_user: User = Depends(get_current_user),
  191. db: Session = Depends(get_db)
  192. ):
  193. """删除聊天历史"""
  194. chat = db.query(ChatHistory)\
  195. .filter(ChatHistory.id == chat_id, ChatHistory.user_id == current_user.id)\
  196. .first()
  197. if not chat:
  198. raise HTTPException(
  199. status_code=status.HTTP_404_NOT_FOUND,
  200. detail="聊天历史不存在或无权访问"
  201. )
  202. # 删除聊天相关的所有消息
  203. db.query(ChatMessage).filter(ChatMessage.chat_id == chat_id).delete()
  204. # 删除聊天
  205. db.delete(chat)
  206. db.commit()
  207. return {"message": "聊天历史已删除"}
  208. @router.put("/{chat_id}", response_model=ChatHistoryResponse)
  209. async def update_chat_history(
  210. chat_id: int,
  211. update_data: ChatHistoryUpdate,
  212. current_user: User = Depends(get_current_user),
  213. db: Session = Depends(get_db)
  214. ):
  215. """更新聊天历史的标题"""
  216. chat = db.query(ChatHistory)\
  217. .filter(ChatHistory.id == chat_id, ChatHistory.user_id == current_user.id)\
  218. .first()
  219. if not chat:
  220. raise HTTPException(
  221. status_code=status.HTTP_404_NOT_FOUND,
  222. detail="聊天历史不存在或无权访问"
  223. )
  224. # 更新标题
  225. if update_data.title:
  226. chat.title = update_data.title
  227. chat.updated_at = datetime.utcnow()
  228. db.commit()
  229. db.refresh(chat)
  230. return chat