application_chat.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # coding=utf-8
  2. """
  3. @project: MaxKB
  4. @Author:虎虎
  5. @file: application_chat_log.py
  6. @date:2025/5/29 17:12
  7. @desc:
  8. """
  9. import uuid_utils.compat as uuid
  10. from django.contrib.postgres.fields import ArrayField
  11. from django.db import models
  12. from django.utils.translation import gettext as _
  13. from langchain_core.messages import HumanMessage, AIMessage
  14. from application.models import Application
  15. from common.encoder.encoder import SystemEncoder
  16. from common.mixins.app_model_mixin import AppModelMixin
  17. from users.models import User
  18. class ChatUserType(models.TextChoices):
  19. ANONYMOUS_USER = "ANONYMOUS_USER", '匿名用户'
  20. CHAT_USER = "CHAT_USER", "对话用户"
  21. SYSTEM_API_KEY = "SYSTEM_API_KEY", "系统API_KEY"
  22. APPLICATION_API_KEY = "APPLICATION_API_KEY", "应用API_KEY"
  23. PLATFORM_USER = "PLATFORM_USER", "平台用户"
  24. def default_asker():
  25. return {'username': '游客'}
  26. class Chat(AppModelMixin):
  27. id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
  28. application = models.ForeignKey(Application, on_delete=models.CASCADE)
  29. abstract = models.CharField(max_length=1024, verbose_name="摘要")
  30. chat_user_id = models.CharField(verbose_name="对话用户id", default=None, null=True)
  31. chat_user_type = models.CharField(max_length=64, verbose_name="客户端类型", choices=ChatUserType.choices,
  32. default=ChatUserType.ANONYMOUS_USER)
  33. is_deleted = models.BooleanField(verbose_name="逻辑删除", default=False)
  34. asker = models.JSONField(verbose_name="访问者", default=default_asker, encoder=SystemEncoder)
  35. meta = models.JSONField(verbose_name="元数据", default=dict)
  36. star_num = models.IntegerField(verbose_name="点赞数量", default=0)
  37. trample_num = models.IntegerField(verbose_name="点踩数量", default=0)
  38. chat_record_count = models.IntegerField(verbose_name="对话次数", default=0)
  39. mark_sum = models.IntegerField(verbose_name="标记数量", default=0)
  40. source = models.JSONField(verbose_name="来源", default=dict)
  41. ip_address = models.CharField(max_length=128, verbose_name="ip地址", default='')
  42. class Meta:
  43. db_table = "application_chat"
  44. class VoteChoices(models.TextChoices):
  45. """订单类型"""
  46. UN_VOTE = "-1", '未投票'
  47. STAR = "0", '赞同'
  48. TRAMPLE = "1", '反对'
  49. class VoteReasonChoices(models.TextChoices):
  50. ACCURATE = 'accurate', '内容准确'
  51. COMPLETE = 'complete', '内容完善'
  52. INACCURATE = 'inaccurate', '内容不准确'
  53. INCOMPLETE = 'incomplete', '内容不完善'
  54. OTHER = 'other', '其他'
  55. class ShareLinkType(models.TextChoices):
  56. PUBLIC = "PUBLIC", 'public'
  57. PRIVATE = "PRIVATE", 'private'
  58. class ChatSourceChoices(models.TextChoices):
  59. ONLINE = "ONLINE", "线上使用"
  60. API_CALL = "API_CALL", "API调用"
  61. ENTERPRISE_WECHAT = "ENTERPRISE_WECHAT", "企业微信"
  62. WECHAT_PUBLIC_ACCOUNT = "WECHAT_PUBLIC_ACCOUNT", "微信公众号"
  63. LARK = "LARK", "飞书"
  64. DINGTALK = "DINGTALK", "钉钉"
  65. ENTERPRISE_WECHAT_ROBOT = "ENTERPRISE_WECHAT_ROBOT", "企业微信机器人"
  66. TRIGGER = "TRIGGER", "触发器"
  67. SLACK = "SLACK", "Slack"
  68. class ChatRecord(AppModelMixin):
  69. """
  70. 对话日志 详情
  71. """
  72. id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
  73. chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
  74. vote_status = models.CharField(verbose_name='投票', max_length=10, choices=VoteChoices.choices,
  75. default=VoteChoices.UN_VOTE)
  76. vote_reason = models.CharField(verbose_name='投票原因', max_length=50, choices=VoteReasonChoices.choices, null=True,
  77. blank=True)
  78. vote_other_content = models.CharField(verbose_name='其他原因', max_length=1024, default='')
  79. problem_text = models.CharField(max_length=10240, verbose_name="问题")
  80. answer_text = models.CharField(max_length=40960, verbose_name="答案")
  81. answer_text_list = ArrayField(verbose_name="改进标注列表",
  82. base_field=models.JSONField()
  83. , default=list)
  84. message_tokens = models.IntegerField(verbose_name="请求token数量", default=0)
  85. answer_tokens = models.IntegerField(verbose_name="响应token数量", default=0)
  86. const = models.IntegerField(verbose_name="总费用", default=0)
  87. details = models.JSONField(verbose_name="对话详情", default=dict, encoder=SystemEncoder)
  88. improve_paragraph_id_list = ArrayField(verbose_name="改进标注列表",
  89. base_field=models.UUIDField(max_length=128, blank=True)
  90. , default=list)
  91. run_time = models.FloatField(verbose_name="运行时长", default=0)
  92. index = models.IntegerField(verbose_name="对话下标")
  93. source = models.JSONField(verbose_name="来源", default=dict)
  94. ip_address = models.CharField(max_length=128, verbose_name="ip地址", default='')
  95. def get_human_message(self):
  96. if 'problem_padding' in self.details:
  97. return HumanMessage(content=self.details.get('problem_padding').get('padding_problem_text'))
  98. return HumanMessage(content=self.problem_text)
  99. def get_ai_message(self):
  100. answer_text = self.answer_text
  101. if answer_text is None or len(str(answer_text).strip()) == 0:
  102. answer_text = _(
  103. 'Sorry, no relevant content was found. Please re-describe your problem or provide more information. ')
  104. return AIMessage(content=answer_text)
  105. def get_node_details_runtime_node_id(self, runtime_node_id):
  106. return self.details.get(runtime_node_id, None)
  107. class Meta:
  108. db_table = "application_chat_record"
  109. class ApplicationChatUserStats(AppModelMixin):
  110. id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
  111. chat_user_id = models.UUIDField(max_length=128, default=uuid.uuid7, verbose_name="对话用户id")
  112. chat_user_type = models.CharField(max_length=64, verbose_name="对话用户类型", choices=ChatUserType.choices,
  113. default=ChatUserType.ANONYMOUS_USER)
  114. application = models.ForeignKey(Application, on_delete=models.CASCADE, verbose_name="应用id")
  115. access_num = models.IntegerField(default=0, verbose_name="访问总次数次数")
  116. intraday_access_num = models.IntegerField(default=0, verbose_name="当日访问次数")
  117. class Meta:
  118. db_table = "application_chat_user_stats"
  119. indexes = [
  120. models.Index(fields=['application_id', 'chat_user_id']),
  121. ]
  122. class ChatShareLink(AppModelMixin):
  123. id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
  124. chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
  125. application = models.ForeignKey(Application,on_delete=models.CASCADE)
  126. share_type = models.CharField(max_length=20, choices=ShareLinkType.choices, default=ShareLinkType.PUBLIC)
  127. user = models.ForeignKey(User, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
  128. chat_record_ids = ArrayField(base_field=models.UUIDField(max_length=128))
  129. class Meta:
  130. db_table = "application_chat_share_link"