intention_service.py 20 KB

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