tag_service.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import uuid
  2. from typing import Optional
  3. import logging
  4. from flask_login import current_user # type: ignore
  5. from sqlalchemy import func
  6. from werkzeug.exceptions import NotFound, Unauthorized
  7. from extensions.ext_database import db
  8. from models.dataset import Dataset
  9. from models.model import App, Tag, TagBinding, AppPermissionAll
  10. from services.errors.tag import TagNameDuplicateError
  11. from services.errors.account import NoPermissionError
  12. from models.account import TenantAccountRole
  13. class TagService:
  14. @staticmethod
  15. def get_tags(tag_type: str, current_tenant_id: str, keyword: Optional[str] = None) -> list:
  16. query = (
  17. db.session.query(Tag.id, Tag.type, Tag.name, func.count(TagBinding.id).label("binding_count"))
  18. .outerjoin(TagBinding, Tag.id == TagBinding.tag_id)
  19. .filter(Tag.type == tag_type, Tag.tenant_id == current_tenant_id)
  20. )
  21. if keyword:
  22. query = query.filter(db.and_(Tag.name.ilike(f"%{keyword}%")))
  23. query = query.group_by(Tag.id, Tag.type, Tag.name)
  24. results: list = query.order_by(Tag.created_at.desc()).all()
  25. return results
  26. @staticmethod
  27. def get_tag_by_tag_name(tag_type: str, tenant_id: str, tag_name: str) -> Optional[Tag]:
  28. tag: Optional[Tag] = (
  29. db.session.query(Tag).filter(Tag.type == tag_type, Tag.tenant_id == tenant_id, Tag.name == tag_name).first()
  30. )
  31. return tag
  32. @staticmethod
  33. def get_target_ids_by_tag_ids(tag_type: str, current_tenant_id: str, tag_ids: list) -> list:
  34. tags = (
  35. db.session.query(Tag)
  36. .filter(Tag.id.in_(tag_ids), Tag.tenant_id == current_tenant_id, Tag.type == tag_type)
  37. .all()
  38. )
  39. if not tags:
  40. return []
  41. tag_ids = [tag.id for tag in tags]
  42. tag_bindings = (
  43. db.session.query(TagBinding.target_id)
  44. .filter(TagBinding.tag_id.in_(tag_ids), TagBinding.tenant_id == current_tenant_id)
  45. .all()
  46. )
  47. if not tag_bindings:
  48. return []
  49. results = [tag_binding.target_id for tag_binding in tag_bindings]
  50. return results
  51. @staticmethod
  52. def get_tags_count(tenant_id: str, keyword: Optional[str] = None) -> int:
  53. query = db.session.query(Tag).filter(Tag.type == "knowledge")
  54. if tenant_id:
  55. query = query.filter(Tag.tenant_id == tenant_id)
  56. if keyword:
  57. query = query.filter(Tag.name.ilike(f"%{keyword}%"))
  58. return query.count()
  59. @staticmethod
  60. def get_tags_by_target_id(tag_type: str, current_tenant_id: str, target_id: str) -> list:
  61. tags = (
  62. db.session.query(Tag)
  63. .join(TagBinding, Tag.id == TagBinding.tag_id)
  64. .filter(
  65. TagBinding.target_id == target_id,
  66. TagBinding.tenant_id == current_tenant_id,
  67. Tag.tenant_id == current_tenant_id,
  68. Tag.type == tag_type,
  69. )
  70. .all()
  71. )
  72. return tags or []
  73. @staticmethod
  74. def get_tag(tag_id: str):
  75. tag = db.session.query(Tag).filter(Tag.id == tag_id).first()
  76. if not tag:
  77. raise NotFound("Tag not found")
  78. return tag
  79. @staticmethod
  80. def get_page_tags(page, per_page, tag_type, tenant_id):
  81. query = (
  82. db.session.query(Tag.id, Tag.type, Tag.name, func.count(TagBinding.id).label("binding_count"))
  83. .outerjoin(TagBinding, Tag.id == TagBinding.tag_id)
  84. .filter(Tag.type == tag_type, Tag.tenant_id == tenant_id)
  85. )
  86. query = query.group_by(Tag.id, Tag.type, Tag.name)
  87. tags = query.paginate(page=page, per_page=per_page, error_out=False)
  88. return tags.items, tags.total
  89. @staticmethod
  90. def save_tags(args: dict) -> Tag:
  91. name = args["name"]
  92. type = args["type"]
  93. tenant_id = current_user.current_tenant_id
  94. tag = TagService.get_tag_by_tag_name(type, tenant_id, name)
  95. if tag:
  96. raise TagNameDuplicateError(f"Tag with name {name} already exists.")
  97. tag = Tag(
  98. id=str(uuid.uuid4()),
  99. name=name,
  100. type=type,
  101. created_by=current_user.id,
  102. tenant_id=tenant_id,
  103. )
  104. db.session.add(tag)
  105. db.session.commit()
  106. return tag
  107. @staticmethod
  108. def update_tags(args: dict, tag_id: str) -> Tag:
  109. tag = db.session.query(Tag).filter(Tag.id == tag_id).first()
  110. if not tag:
  111. raise NotFound("Tag not found")
  112. tag.name = args["name"]
  113. db.session.commit()
  114. return tag
  115. @staticmethod
  116. def get_tag_binding_count(tag_id: str) -> int:
  117. count = db.session.query(TagBinding).filter(TagBinding.tag_id == tag_id).count()
  118. return count
  119. @staticmethod
  120. def delete_tag(tag_id: str):
  121. tag = db.session.query(Tag).filter(Tag.id == tag_id).first()
  122. if not tag:
  123. raise NotFound("Tag not found")
  124. db.session.delete(tag)
  125. # delete tag binding
  126. tag_bindings = db.session.query(TagBinding).filter(TagBinding.tag_id == tag_id).all()
  127. if tag_bindings:
  128. for tag_binding in tag_bindings:
  129. db.session.delete(tag_binding)
  130. db.session.commit()
  131. @staticmethod
  132. def save_tag_binding(args):
  133. # 1.智能体设置可见授权的编辑权限一致,2.知识库的标签都能设置--修改为随设置权限一致
  134. TagService.check_target_edit_auth(args["type"], args["target_id"])
  135. # check if target exists
  136. TagService.check_target_exists(args["type"], args["target_id"])
  137. # save tag binding
  138. for tag_id in args["tag_ids"]:
  139. tag_binding = (
  140. db.session.query(TagBinding)
  141. .filter(TagBinding.tag_id == tag_id, TagBinding.target_id == args["target_id"])
  142. .first()
  143. )
  144. if tag_binding:
  145. continue
  146. new_tag_binding = TagBinding(
  147. tag_id=tag_id,
  148. target_id=args["target_id"],
  149. tenant_id=current_user.current_tenant_id,
  150. created_by=current_user.id,
  151. )
  152. db.session.add(new_tag_binding)
  153. db.session.commit()
  154. @staticmethod
  155. def delete_tag_binding(args):
  156. TagService.check_target_edit_auth(args["type"], args["target_id"])
  157. # check if target exists
  158. TagService.check_target_exists(args["type"], args["target_id"])
  159. # delete tag binding
  160. tag_bindings = (
  161. db.session.query(TagBinding)
  162. .filter(TagBinding.target_id == args["target_id"], TagBinding.tag_id == (args["tag_id"]))
  163. .first()
  164. )
  165. if tag_bindings:
  166. db.session.delete(tag_bindings)
  167. db.session.commit()
  168. @staticmethod
  169. def check_target_exists(type: str, target_id: str):
  170. if type in {"knowledge", "knowledge_category"}:
  171. dataset = (
  172. db.session.query(Dataset)
  173. .filter(Dataset.tenant_id == current_user.current_tenant_id, Dataset.id == target_id)
  174. .first()
  175. )
  176. if not dataset:
  177. raise NotFound("Dataset not found")
  178. elif type == "app":
  179. app = (
  180. db.session.query(App)
  181. .filter(App.tenant_id == current_user.current_tenant_id, App.id == target_id)
  182. .first()
  183. )
  184. if not app:
  185. raise NotFound("App not found")
  186. else:
  187. raise NotFound("Invalid binding type")
  188. @staticmethod
  189. def check_target_edit_auth(type: str, target_id: str):
  190. if type in {"knowledge", "knowledge_category"}:
  191. dataset = (
  192. db.session.query(Dataset)
  193. .filter(Dataset.id == target_id)
  194. .first()
  195. )
  196. if (
  197. current_user.current_role not in [TenantAccountRole.ADMIN, TenantAccountRole.OWNER]
  198. and dataset.created_by != current_user.id
  199. ):
  200. raise NoPermissionError("You do not have permission to operate this dataset.")
  201. elif type == "app":
  202. app = (
  203. db.session.query(AppPermissionAll)
  204. .filter(AppPermissionAll.has_read_permission == True,
  205. AppPermissionAll.account_id == current_user.id,
  206. AppPermissionAll.app_id == target_id)
  207. .first()
  208. )
  209. if not app:
  210. raise NoPermissionError("You do not have permission to operate this app.")
  211. else:
  212. raise NotFound("Invalid binding type")