scenario_topic_service.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. """
  2. 情景话题对话记录服务:查询已完成话题、写入对话记录
  3. """
  4. import logging
  5. from typing import Dict, List
  6. from sqlalchemy import select, func
  7. from sqlalchemy.exc import IntegrityError
  8. from database import db_manager
  9. from models_db import UserSpecialScenarioTopicLog
  10. logger = logging.getLogger(__name__)
  11. class ScenarioTopicService:
  12. """用户情景话题对话记录"""
  13. def __init__(self):
  14. self.db = db_manager
  15. async def set_db_manager(self, manager):
  16. self.db = manager
  17. async def get_completed_count_per_scenario(self, user_id: str) -> Dict[str, int]:
  18. """
  19. 按场景统计该用户已完成(已对话)的话题数。
  20. Returns: {"window": 2, "reading": 0, "eating": 3},仅包含特殊场景。
  21. """
  22. try:
  23. async with self.db.get_session() as session:
  24. result = await session.execute(
  25. select(
  26. UserSpecialScenarioTopicLog.scenario_key,
  27. func.count(UserSpecialScenarioTopicLog.id).label("cnt"),
  28. )
  29. .where(UserSpecialScenarioTopicLog.user_id == user_id)
  30. .group_by(UserSpecialScenarioTopicLog.scenario_key)
  31. )
  32. rows = result.all()
  33. return {row.scenario_key: row.cnt for row in rows}
  34. except Exception as e:
  35. logger.warning(f"[ScenarioTopic] get_completed_count_per_scenario failed: user_id={user_id}, e={e}")
  36. return {}
  37. async def get_done_topic_keys(self, user_id: str, scenario_key: str) -> List[str]:
  38. """获取该用户在该场景下已对话过的话题 key 列表。"""
  39. try:
  40. async with self.db.get_session() as session:
  41. result = await session.execute(
  42. select(UserSpecialScenarioTopicLog.topic_key).where(
  43. UserSpecialScenarioTopicLog.user_id == user_id,
  44. UserSpecialScenarioTopicLog.scenario_key == scenario_key,
  45. )
  46. )
  47. rows = result.all()
  48. return [r.topic_key for r in rows]
  49. except Exception as e:
  50. logger.warning(f"[ScenarioTopic] get_done_topic_keys failed: user_id={user_id}, scenario={scenario_key}, e={e}")
  51. return []
  52. async def record_conversation(self, user_id: str, scenario_key: str, topic_key: str) -> bool:
  53. """
  54. 记录用户在该场景该话题下进行了对话。同一 (user_id, scenario_key, topic_key) 只插入一次。
  55. """
  56. if not user_id or not scenario_key or not topic_key:
  57. return False
  58. try:
  59. async with self.db.get_session() as session:
  60. log = UserSpecialScenarioTopicLog(
  61. user_id=user_id,
  62. scenario_key=scenario_key,
  63. topic_key=topic_key,
  64. )
  65. session.add(log)
  66. await session.commit()
  67. logger.info(f"[ScenarioTopic] recorded: user_id={user_id}, scenario={scenario_key}, topic={topic_key}")
  68. return True
  69. except IntegrityError:
  70. # 唯一约束冲突,说明已记录过,视为成功
  71. return True
  72. except Exception as e:
  73. logger.warning(f"[ScenarioTopic] record_conversation failed: user_id={user_id}, scenario={scenario_key}, topic={topic_key}, e={e}")
  74. return False
  75. scenario_topic_service = ScenarioTopicService()