characters.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """
  2. AI角色管理API
  3. """
  4. from fastapi import APIRouter, Depends, HTTPException
  5. from sqlalchemy.ext.asyncio import AsyncSession
  6. from sqlalchemy import select
  7. from app.core.database import get_db
  8. from app.models.user import User
  9. from app.models.character import Character
  10. from app.schemas.character import CharacterCreate, CharacterResponse, CharacterUpdate
  11. from app.api.auth import get_current_user
  12. from typing import List
  13. router = APIRouter()
  14. def generate_system_prompt(character_data: CharacterCreate) -> str:
  15. """根据角色信息生成系统提示词"""
  16. prompt = f"""你是{character_data.name}。
  17. 性格特点:{character_data.personality or '友好、乐于助人'}
  18. 背景故事:{character_data.background_story or '无特殊背景'}
  19. 重要指示:
  20. 1. 始终保持角色一致性,用第一人称"我"来回答
  21. 2. 根据对话内容在回复末尾附带情感分析(JSON格式)
  22. 3. 使用{character_data.language}语言回复
  23. 4. 回复自然、真实,避免机械感
  24. 情感分析格式(必须包含在每次回复中):
  25. <sentiment>{{"affection_change": -5到5的整数, "reason": "简短说明"}}</sentiment>
  26. 示例:
  27. 用户:今天心情不太好
  28. 你:怎么了?发生什么事了吗?愿意和我聊聊吗?<sentiment>{{"affection_change": 2, "reason": "用户主动分享情绪,表示信任"}}</sentiment>
  29. """
  30. return prompt
  31. @router.post("", response_model=CharacterResponse)
  32. async def create_character(
  33. character_data: CharacterCreate,
  34. current_user: User = Depends(get_current_user),
  35. db: AsyncSession = Depends(get_db)
  36. ):
  37. """创建AI角色"""
  38. # 生成系统提示词
  39. system_prompt = generate_system_prompt(character_data)
  40. character = Character(
  41. user_id=current_user.id,
  42. name=character_data.name,
  43. personality=character_data.personality,
  44. background_story=character_data.background_story,
  45. avatar_url=character_data.avatar_url,
  46. language=character_data.language,
  47. llm_provider=character_data.llm_provider,
  48. llm_model=character_data.llm_model,
  49. system_prompt=system_prompt,
  50. config=character_data.config
  51. )
  52. db.add(character)
  53. await db.commit()
  54. await db.refresh(character)
  55. return character
  56. @router.get("", response_model=List[CharacterResponse])
  57. async def list_characters(
  58. current_user: User = Depends(get_current_user),
  59. db: AsyncSession = Depends(get_db)
  60. ):
  61. """获取用户的所有AI角色"""
  62. result = await db.execute(
  63. select(Character)
  64. .where(Character.user_id == current_user.id, Character.is_active == True)
  65. .order_by(Character.created_at.desc())
  66. )
  67. characters = result.scalars().all()
  68. return characters
  69. @router.get("/{character_id}", response_model=CharacterResponse)
  70. async def get_character(
  71. character_id: int,
  72. current_user: User = Depends(get_current_user),
  73. db: AsyncSession = Depends(get_db)
  74. ):
  75. """获取AI角色详情"""
  76. result = await db.execute(
  77. select(Character).where(
  78. Character.id == character_id,
  79. Character.user_id == current_user.id
  80. )
  81. )
  82. character = result.scalar_one_or_none()
  83. if not character:
  84. raise HTTPException(status_code=404, detail="角色不存在")
  85. return character
  86. @router.put("/{character_id}", response_model=CharacterResponse)
  87. async def update_character(
  88. character_id: int,
  89. character_data: CharacterUpdate,
  90. current_user: User = Depends(get_current_user),
  91. db: AsyncSession = Depends(get_db)
  92. ):
  93. """更新AI角色"""
  94. result = await db.execute(
  95. select(Character).where(
  96. Character.id == character_id,
  97. Character.user_id == current_user.id
  98. )
  99. )
  100. character = result.scalar_one_or_none()
  101. if not character:
  102. raise HTTPException(status_code=404, detail="角色不存在")
  103. # 更新字段
  104. update_data = character_data.dict(exclude_unset=True)
  105. for field, value in update_data.items():
  106. setattr(character, field, value)
  107. # 如果更新了基础信息,重新生成系统提示词
  108. if any(k in update_data for k in ['name', 'personality', 'background_story', 'language']):
  109. character.system_prompt = generate_system_prompt(CharacterCreate(**character.__dict__))
  110. await db.commit()
  111. await db.refresh(character)
  112. return character
  113. @router.delete("/{character_id}")
  114. async def delete_character(
  115. character_id: int,
  116. current_user: User = Depends(get_current_user),
  117. db: AsyncSession = Depends(get_db)
  118. ):
  119. """删除AI角色"""
  120. result = await db.execute(
  121. select(Character).where(
  122. Character.id == character_id,
  123. Character.user_id == current_user.id
  124. )
  125. )
  126. character = result.scalar_one_or_none()
  127. if not character:
  128. raise HTTPException(status_code=404, detail="角色不存在")
  129. await db.delete(character)
  130. await db.commit()
  131. return {"message": "角色已删除"}