intention_service.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. import logging
  2. import uuid
  3. from datetime import datetime
  4. from typing import Optional
  5. from flask_login import current_user
  6. from werkzeug.exceptions import Forbidden, NotFound
  7. from extensions.ext_database import db
  8. from models.intention import (
  9. Intention,
  10. IntentionCorpus,
  11. IntentionCorpusSimilarityQuestion,
  12. IntentionKeyword,
  13. IntentionType,
  14. )
  15. from services.errors.intention import (
  16. IntentionCorpusQuestionDuplicateError,
  17. IntentionKeywordNameDuplicateError,
  18. IntentionNameDuplicateError,
  19. IntentionTypeNameDuplicateError,
  20. )
  21. class IntentionTypeService:
  22. @staticmethod
  23. def get_intention_types(page, per_page, search=None):
  24. query = IntentionType.query.order_by(IntentionType.created_at.desc())
  25. if search:
  26. query = query.filter(IntentionType.name.like(f"%{search}%"))
  27. intention_types = query.paginate(page=page, per_page=per_page, error_out=False)
  28. return intention_types.items, intention_types.total
  29. @staticmethod
  30. def save_intention_type(args: dict) -> IntentionType:
  31. name = args["name"]
  32. intention_type = IntentionTypeService.get_intention_type_by_name(name)
  33. if intention_type:
  34. raise IntentionTypeNameDuplicateError(f"IntentionType with name {name} already exists.")
  35. intention_type = IntentionType(
  36. id=str(uuid.uuid4()),
  37. name=name,
  38. created_by=current_user.id,
  39. created_at=datetime.now(),
  40. )
  41. db.session.add(intention_type)
  42. db.session.commit()
  43. return intention_type
  44. @staticmethod
  45. def update_intention_type(id: str, args: dict) -> IntentionType:
  46. intention_type = IntentionTypeService.get_intention_type(id)
  47. if not intention_type:
  48. raise NotFound("IntentionType not found")
  49. name = args["name"]
  50. intention_type_new = IntentionType.query.filter(
  51. IntentionType.id != intention_type.id,
  52. IntentionType.name == name,
  53. ).first()
  54. if intention_type_new:
  55. raise IntentionTypeNameDuplicateError(f"IntentionType with name {name} already exists.")
  56. intention_type.name = name
  57. intention_type.updated_by = current_user.id
  58. intention_type.updated_at = datetime.now()
  59. db.session.add(intention_type)
  60. db.session.commit()
  61. return intention_type
  62. @staticmethod
  63. def delete_intention_type(id: str):
  64. intention_type = IntentionTypeService.get_intention_type(id)
  65. if not intention_type:
  66. raise NotFound("IntentionType not found")
  67. db.session.delete(intention_type)
  68. db.session.commit()
  69. return intention_type
  70. @staticmethod
  71. def get_intention_type(id: str) -> Optional[IntentionType]:
  72. intention_type: Optional[IntentionType] = IntentionType.query.filter_by(id=id).first()
  73. return intention_type
  74. @staticmethod
  75. def get_intention_type_by_name(name: str) -> Optional[IntentionType]:
  76. intention_type: Optional[IntentionType] = IntentionType.query.filter_by(name=name).first()
  77. return intention_type
  78. class IntentionService:
  79. @staticmethod
  80. def get_intentions(page, per_page, type_id=None, name_search=None):
  81. query = Intention.query.order_by(Intention.created_at.desc())
  82. if type_id:
  83. query = query.filter(Intention.type_id == type_id)
  84. if name_search:
  85. query = query.filter(Intention.name.ilike(f"%{name_search}%"))
  86. intentions = query.paginate(page=page, per_page=per_page, error_out=False)
  87. return intentions.items, intentions.total
  88. @staticmethod
  89. def save_intention(args: dict) -> Intention:
  90. name = args["name"]
  91. intention = IntentionService.get_intention_by_name(name)
  92. if intention:
  93. raise IntentionNameDuplicateError(f"Intention with name {name} already exists.")
  94. type_id = args["type_id"]
  95. intention_type = IntentionTypeService.get_intention_type(type_id)
  96. if not intention_type:
  97. raise NotFound("IntentionType not found")
  98. intention = Intention(
  99. id=str(uuid.uuid4()),
  100. name=name,
  101. type_id=type_id,
  102. created_by=current_user.id,
  103. created_at=datetime.now(),
  104. )
  105. db.session.add(intention)
  106. db.session.commit()
  107. return intention
  108. @staticmethod
  109. def update_intention(intention_id: str, args: dict) -> Intention:
  110. intention: Optional[Intention] = IntentionService.get_intention(intention_id)
  111. if not intention:
  112. raise NotFound("Intention not found")
  113. name = args["name"]
  114. intention_new = Intention.query.filter(Intention.id != intention.id, Intention.name == name).first()
  115. if intention_new:
  116. raise IntentionNameDuplicateError(f"Intention with name {name} already exists.")
  117. intention.name = name
  118. type_id = args["type_id"]
  119. intention_type = IntentionTypeService.get_intention_type(type_id)
  120. if not intention_type:
  121. raise NotFound("IntentionType not found")
  122. intention.type_id = type_id
  123. intention.updated_by = current_user.id
  124. intention.updated_at = datetime.now()
  125. db.session.add(intention)
  126. db.session.commit()
  127. return intention
  128. @staticmethod
  129. def delete_intention(intention_id: str):
  130. intention: Optional[Intention] = IntentionService.get_intention(intention_id)
  131. if not intention:
  132. raise NotFound("Intention not found")
  133. # 1.若存在关键词,则无法删除
  134. if intention.keywords_count > 0:
  135. raise Forbidden(
  136. f"You are not allowed to delete intention, because {intention.keywords_count} keywords were found."
  137. )
  138. # 2.若关联训练预料,则无法删除
  139. if intention.corpus_count > 0:
  140. raise Forbidden(
  141. f"You are not allowed to delete intention, because {intention.corpus_count} corpus were found."
  142. )
  143. db.session.delete(intention)
  144. db.session.commit()
  145. return intention
  146. @staticmethod
  147. def get_intention(intention_id: str) -> Optional[Intention]:
  148. intention: Optional[Intention] = Intention.query.filter(Intention.id == intention_id).first()
  149. return intention
  150. @staticmethod
  151. def get_intention_by_name(name: str) -> Optional[Intention]:
  152. intention: Optional[Intention] = Intention.query.filter(Intention.name == name).first()
  153. return intention
  154. class IntentionKeywordService:
  155. @staticmethod
  156. def get_intention_keywords(intention_id: str, search=None):
  157. query = IntentionKeyword.query.filter_by(intention_id=intention_id)
  158. if search:
  159. query = query.filter(IntentionKeyword.name.ilike(f"%{search}%"))
  160. intention_keywords = query.all()
  161. return intention_keywords
  162. @staticmethod
  163. def save_intention_keyword(intention_id: str, args: dict) -> IntentionKeyword:
  164. name = args["name"]
  165. intention_keyword = IntentionKeywordService.get_intention_keyword_by_name(intention_id, name)
  166. if intention_keyword:
  167. raise IntentionKeywordNameDuplicateError(f"IntentionKeyword with name {name} already exists.")
  168. intention_keyword = IntentionKeyword(
  169. id=str(uuid.uuid4()),
  170. intention_id=intention_id,
  171. name=name,
  172. created_by=current_user.id,
  173. created_at=datetime.now(),
  174. )
  175. db.session.add(intention_keyword)
  176. db.session.commit()
  177. return intention_keyword
  178. @staticmethod
  179. def update_intention_keyword(intention_keyword_id: str, args: dict) -> IntentionKeyword:
  180. intention_keyword = IntentionKeywordService.get_intention_keyword(intention_keyword_id)
  181. if not intention_keyword:
  182. raise NotFound("IntentionKeyword not found")
  183. name = args["name"]
  184. intention_keyword_new = IntentionKeyword.query.filter(
  185. IntentionKeyword.id != intention_keyword.id, IntentionKeyword.name == name
  186. ).first()
  187. if intention_keyword_new:
  188. raise IntentionKeywordNameDuplicateError(f"IntentionKeyword with name {name} already exists.")
  189. intention_keyword.name = name
  190. intention_id = args["intention_id"]
  191. intention = IntentionService.get_intention(intention_id)
  192. if not intention:
  193. raise NotFound("Intention not found")
  194. intention_keyword.intention_id = intention_id
  195. intention_keyword.updated_by = current_user.id
  196. intention_keyword.updated_at = datetime.now()
  197. db.session.add(intention_keyword)
  198. db.session.commit()
  199. return intention_keyword
  200. @staticmethod
  201. def delete_intention_keyword(intention_keyword_id: str):
  202. intention_keyword = IntentionKeywordService.get_intention_keyword(intention_keyword_id)
  203. if not intention_keyword:
  204. raise NotFound("IntentionKeyword not found")
  205. db.session.delete(intention_keyword)
  206. db.session.commit()
  207. @staticmethod
  208. def delete_intention_keywords(intention_keyword_ids: list[str]):
  209. intention_keywords = IntentionKeyword.query.filter(IntentionKeyword.id.in_(intention_keyword_ids)).all()
  210. for intention_keyword in intention_keywords:
  211. db.session.delete(intention_keyword)
  212. db.session.commit()
  213. @staticmethod
  214. def delete_intention_keywords_by_intention_id(intention_id: str):
  215. intention_keywords = IntentionKeyword.query.filter(IntentionKeyword.intention_id == intention_id).all()
  216. for intention_keyword in intention_keywords:
  217. db.session.delete(intention_keyword)
  218. db.session.commit()
  219. @staticmethod
  220. def get_intention_keyword(intention_keyword_id: str) -> Optional[IntentionKeyword]:
  221. intention_keyword: Optional[IntentionKeyword] = IntentionKeyword.query.filter_by(
  222. id=intention_keyword_id
  223. ).first()
  224. return intention_keyword
  225. @staticmethod
  226. def get_intention_keyword_by_name(intention_id, name: str) -> Optional[IntentionKeyword]:
  227. intention_keyword: Optional[IntentionKeyword] = IntentionKeyword.query.filter(
  228. IntentionKeyword.intention_id == intention_id,
  229. IntentionKeyword.name == name,
  230. ).first()
  231. return intention_keyword
  232. class IntentionCorpusService:
  233. @staticmethod
  234. def get_intention_corpus(corpus_id: str) -> Optional[IntentionCorpus]:
  235. intention_corpus: Optional[IntentionCorpus] = IntentionCorpus.query.filter(
  236. IntentionCorpus.id == corpus_id
  237. ).first()
  238. return intention_corpus
  239. @staticmethod
  240. def get_page_intention_corpus(page, per_page, search=None, intention_id=None):
  241. query = IntentionCorpus.query.order_by(IntentionCorpus.created_at.desc())
  242. if search:
  243. query = query.filter(IntentionCorpus.question.like(f"%{search}%"))
  244. if intention_id:
  245. query = query.filter(IntentionCorpus.intention_id == intention_id)
  246. intention_corpus = query.paginate(page=page, per_page=per_page, error_out=False)
  247. return intention_corpus.items, intention_corpus.total
  248. @staticmethod
  249. def get_intention_corpus_by_question(question: str) -> Optional[IntentionCorpus]:
  250. intention_corpus: Optional[IntentionCorpus] = IntentionCorpus.query.filter(
  251. IntentionCorpus.question == question
  252. ).first()
  253. return intention_corpus
  254. @staticmethod
  255. def save_intention_corpus(args: dict):
  256. question = args["question"]
  257. intention_corpus = IntentionCorpusService.get_intention_corpus_by_question(question)
  258. if intention_corpus:
  259. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  260. intention_id = args["intention_id"]
  261. intention = IntentionService.get_intention(intention_id)
  262. if not intention:
  263. raise NotFound(f"Intention with id {intention_id} not found")
  264. intention_corpus = IntentionCorpus(
  265. id=str(uuid.uuid4()),
  266. question=question,
  267. intention_id=intention_id,
  268. created_by=current_user.id,
  269. created_at=datetime.now(),
  270. )
  271. if "question_config" in args:
  272. intention_corpus.question_config = args["question_config"]
  273. db.session.add(intention_corpus)
  274. db.session.commit()
  275. return intention_corpus
  276. @staticmethod
  277. def update_intention_corpus(corpus_id: str, args: dict):
  278. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  279. if not intention_corpus:
  280. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  281. if "question" in args:
  282. question = args["question"]
  283. intention_corpus_new = IntentionCorpus.query.filter(
  284. IntentionCorpus.id != corpus_id, IntentionCorpus.question == question
  285. ).first()
  286. if intention_corpus_new:
  287. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  288. intention_corpus.question = question
  289. if "question_config" in args:
  290. intention_corpus.question_config = args["question_config"]
  291. if "intention_id" in args:
  292. intention_id = args["intention_id"]
  293. intention = IntentionService.get_intention(intention_id)
  294. if not intention:
  295. raise NotFound(f"Intention with id {intention_id} not found")
  296. intention_corpus.intention_id = intention.id
  297. intention_corpus.updated_at = datetime.now()
  298. intention_corpus.updated_by = current_user.id
  299. db.session.add(intention_corpus)
  300. db.session.commit()
  301. return intention_corpus
  302. @staticmethod
  303. def delete_intention_corpus_by_id(corpus_id: str):
  304. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  305. if not intention_corpus:
  306. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  307. IntentionCorpusService.delete_intention_corpus(intention_corpus)
  308. @staticmethod
  309. def delete_intention_corpus(intention_corpus: IntentionCorpus):
  310. similarity_questions = intention_corpus.similarity_questions
  311. if similarity_questions:
  312. raise Forbidden(f"存在与其关联的相似问题,无法删除Id为{intention_corpus.id}训练语料")
  313. db.session.delete(intention_corpus)
  314. db.session.commit()
  315. class IntentionCorpusSimilarityQuestionService:
  316. @staticmethod
  317. def save_similarity_question(corpus_id: str, args: dict):
  318. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  319. if not intention_corpus:
  320. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  321. question = args["question"]
  322. intention_corpus_similarity_question = (
  323. IntentionCorpusSimilarityQuestionService.get_similarity_question_by_question(question)
  324. )
  325. if intention_corpus_similarity_question:
  326. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  327. intention_corpus_similarity_question = IntentionCorpusSimilarityQuestion(
  328. id=str(uuid.uuid4()),
  329. question=question,
  330. corpus_id=corpus_id,
  331. created_by=current_user.id,
  332. created_at=datetime.now(),
  333. )
  334. if "question_config" in args:
  335. intention_corpus_similarity_question.question_config = args["question_config"]
  336. db.session.add(intention_corpus_similarity_question)
  337. db.session.commit()
  338. return intention_corpus_similarity_question
  339. @staticmethod
  340. def update_similarity_question(similarity_question_id: str, args: dict):
  341. similarity_question = IntentionCorpusSimilarityQuestionService.get_similarity_question(similarity_question_id)
  342. if not similarity_question:
  343. raise NotFound(f"IntentionCorpus with id {similarity_question_id} not found")
  344. if "corpus_id" in args:
  345. corpus_id = args["corpus_id"]
  346. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  347. if not intention_corpus:
  348. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  349. similarity_question.corpus_id = corpus_id
  350. if "question" in args:
  351. similarity_question.question = args["question"]
  352. if "question_config" in args:
  353. similarity_question.question_config = args["question_config"]
  354. db.session.add(similarity_question)
  355. db.session.commit()
  356. return similarity_question
  357. @staticmethod
  358. def get_similarity_question(similarity_question_id: str) -> Optional[IntentionCorpusSimilarityQuestion]:
  359. similarity_question: Optional[IntentionCorpus] = IntentionCorpusSimilarityQuestion.query.filter_by(
  360. id=similarity_question_id
  361. ).first()
  362. return similarity_question
  363. @staticmethod
  364. def get_similarity_question_by_question(question: str) -> Optional[IntentionCorpusSimilarityQuestion]:
  365. similarity_question: Optional[IntentionCorpusSimilarityQuestion] = (
  366. IntentionCorpusSimilarityQuestion.query.filter_by(question=question).first()
  367. )
  368. return similarity_question
  369. @staticmethod
  370. def get_similarity_questions_by_corpus_id_like_question(corpus_id, search=None):
  371. query = IntentionCorpusSimilarityQuestion.query.filter(
  372. IntentionCorpusSimilarityQuestion.corpus_id == corpus_id
  373. ).order_by(IntentionCorpusSimilarityQuestion.created_at.desc())
  374. if search:
  375. query = query.filter(IntentionCorpusSimilarityQuestion.question.ilike(f"%{search}%"))
  376. similarity_questions = query.all()
  377. return similarity_questions
  378. @staticmethod
  379. def delete_similarity_question_by_corpus_id(corpus_id: str):
  380. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  381. if not intention_corpus:
  382. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  383. logging.info(intention_corpus.similarity_questions)
  384. IntentionCorpusSimilarityQuestionService.delete_similarity_questions(intention_corpus.similarity_questions)
  385. @staticmethod
  386. def delete_similarity_question_by_id(similarity_question_id: str):
  387. similarity_question = IntentionCorpusSimilarityQuestionService.get_similarity_question(similarity_question_id)
  388. if not similarity_question:
  389. raise NotFound(f"IntentionCorpus with id {similarity_question_id} not found")
  390. IntentionCorpusSimilarityQuestionService.delete_similarity_question(similarity_question)
  391. @staticmethod
  392. def delete_similarity_question(similarity_question: IntentionCorpusSimilarityQuestion):
  393. db.session.delete(similarity_question)
  394. db.session.commit()
  395. @staticmethod
  396. def delete_similarity_questions_by_ids(similarity_question_ids: list[str]):
  397. similarity_questions = IntentionCorpusSimilarityQuestion.query.filter(
  398. IntentionCorpusSimilarityQuestion.id.in_(similarity_question_ids)
  399. ).all()
  400. IntentionCorpusSimilarityQuestionService.delete_similarity_questions(similarity_questions)
  401. @staticmethod
  402. def delete_similarity_questions(similarity_questions: list[IntentionCorpusSimilarityQuestion]):
  403. if not similarity_questions:
  404. return
  405. for similarity_question in similarity_questions:
  406. db.session.delete(similarity_question)
  407. db.session.commit()