intention_service.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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. IntentionTrainFile,
  14. IntentionTrainFileBinding,
  15. IntentionTrainTask,
  16. IntentionType,
  17. )
  18. from services.errors.intention import (
  19. IntentionCorpusQuestionDuplicateError,
  20. IntentionKeywordNameDuplicateError,
  21. IntentionNameDuplicateError,
  22. IntentionTrainFileDuplicateError,
  23. IntentionTypeNameDuplicateError,
  24. )
  25. class IntentionTypeService:
  26. @staticmethod
  27. def get_intention_types(page, per_page, search=None):
  28. query = IntentionType.query.order_by(IntentionType.created_at.desc())
  29. if search:
  30. query = query.filter(IntentionType.name.like(f"%{search}%"))
  31. intention_types = query.paginate(page=page, per_page=per_page, error_out=False)
  32. return intention_types.items, intention_types.total
  33. @staticmethod
  34. def save_intention_type(args: dict) -> IntentionType:
  35. name = args['name']
  36. intention_type = IntentionTypeService.get_intention_type_by_name(name)
  37. if intention_type:
  38. raise IntentionTypeNameDuplicateError(f"IntentionType with name {name} already exists.")
  39. intention_type = IntentionType(
  40. id=str(uuid.uuid4()),
  41. name=name,
  42. created_by=current_user.id,
  43. created_at=datetime.now(),
  44. )
  45. db.session.add(intention_type)
  46. db.session.commit()
  47. return intention_type
  48. @staticmethod
  49. def update_intention_type(id: str, args: dict) -> IntentionType:
  50. intention_type = IntentionTypeService.get_intention_type(id)
  51. if not intention_type:
  52. raise NotFound("IntentionType not found")
  53. name = args['name']
  54. intention_type_new = (
  55. IntentionType.query.filter(
  56. IntentionType.id != intention_type.id,
  57. IntentionType.name == name,
  58. ).first()
  59. )
  60. if intention_type_new:
  61. raise IntentionTypeNameDuplicateError(f"IntentionType with name {name} already exists.")
  62. intention_type.name = name
  63. intention_type.updated_by = current_user.id
  64. intention_type.updated_at = datetime.now()
  65. db.session.add(intention_type)
  66. db.session.commit()
  67. return intention_type
  68. @staticmethod
  69. def delete_intention_type(id: str):
  70. intention_type = IntentionTypeService.get_intention_type(id)
  71. if not intention_type:
  72. raise NotFound("IntentionType not found")
  73. db.session.delete(intention_type)
  74. db.session.commit()
  75. return intention_type
  76. @staticmethod
  77. def get_intention_type(id: str) -> Optional[IntentionType]:
  78. intention_type: Optional[IntentionType] = IntentionType.query.filter_by(id=id).first()
  79. return intention_type
  80. @staticmethod
  81. def get_intention_type_by_name(name: str) -> Optional[IntentionType]:
  82. intention_type: Optional[IntentionType] = IntentionType.query.filter_by(name=name).first()
  83. return intention_type
  84. class IntentionService:
  85. @staticmethod
  86. def get_intentions(page, per_page, type_id=None, name_search=None):
  87. query = Intention.query.order_by(Intention.created_at.desc())
  88. if type_id:
  89. query = query.filter(Intention.type_id == type_id)
  90. if name_search:
  91. query = query.filter(Intention.name.ilike(f"%{name_search}%"))
  92. intentions = query.paginate(page=page, per_page=per_page, error_out=False)
  93. return intentions.items, intentions.total
  94. @staticmethod
  95. def save_intention(args: dict) -> Intention:
  96. name = args["name"]
  97. intention = IntentionService.get_intention_by_name(name)
  98. if intention:
  99. raise IntentionNameDuplicateError(f"Intention with name {name} already exists.")
  100. type_id = args["type_id"]
  101. intention_type = IntentionTypeService.get_intention_type(type_id)
  102. if not intention_type:
  103. raise NotFound("IntentionType not found")
  104. intention = Intention(
  105. id=str(uuid.uuid4()),
  106. name=name,
  107. type_id=type_id,
  108. created_by=current_user.id,
  109. created_at=datetime.now(),
  110. )
  111. db.session.add(intention)
  112. db.session.commit()
  113. return intention
  114. @staticmethod
  115. def update_intention(intention_id: str, args: dict) -> Intention:
  116. intention: Optional[Intention] = IntentionService.get_intention(intention_id)
  117. if not intention:
  118. raise NotFound("Intention not found")
  119. name = args["name"]
  120. intention_new = (
  121. Intention.query.filter(
  122. Intention.id != intention.id,
  123. Intention.name == name
  124. ).first()
  125. )
  126. if intention_new:
  127. raise IntentionNameDuplicateError(f"Intention with name {name} already exists.")
  128. intention.name = name
  129. type_id = args["type_id"]
  130. intention_type = IntentionTypeService.get_intention_type(type_id)
  131. if not intention_type:
  132. raise NotFound("IntentionType not found")
  133. intention.type_id = type_id
  134. intention.updated_by = current_user.id
  135. intention.updated_at = datetime.now()
  136. db.session.add(intention)
  137. db.session.commit()
  138. return intention
  139. @staticmethod
  140. def delete_intention(intention_id: str):
  141. intention: Optional[Intention] = IntentionService.get_intention(intention_id)
  142. if not intention:
  143. raise NotFound("Intention not found")
  144. # 1.若存在关键词,则无法删除
  145. if intention.keywords_count > 0:
  146. raise Forbidden(f"You are not allowed to delete intention, "
  147. f"because {intention.keywords_count} keywords were found.")
  148. # 2.若关联训练预料,则无法删除
  149. if intention.corpus_count > 0:
  150. raise Forbidden(f"You are not allowed to delete intention, "
  151. f"because {intention.corpus_count} corpus were found.")
  152. db.session.delete(intention)
  153. db.session.commit()
  154. return intention
  155. @staticmethod
  156. def get_intention(intention_id: str) -> Optional[Intention]:
  157. intention: Optional[Intention] = Intention.query.filter(Intention.id == intention_id).first()
  158. return intention
  159. @staticmethod
  160. def get_intention_by_name(name: str) -> Optional[Intention]:
  161. intention: Optional[Intention] = Intention.query.filter(Intention.name == name).first()
  162. return intention
  163. class IntentionKeywordService:
  164. @staticmethod
  165. def get_intention_keywords(intention_id: str, search=None):
  166. query = IntentionKeyword.query.filter_by(intention_id=intention_id)
  167. if search:
  168. query = query.filter(IntentionKeyword.name.ilike(f"%{search}%"))
  169. intention_keywords = query.all()
  170. return intention_keywords
  171. @staticmethod
  172. def save_intention_keyword(intention_id: str, args: dict) -> IntentionKeyword:
  173. name = args["name"]
  174. intention_keyword = IntentionKeywordService.get_intention_keyword_by_name(intention_id, name)
  175. if intention_keyword:
  176. raise IntentionKeywordNameDuplicateError(f"IntentionKeyword with name {name} already exists.")
  177. intention_keyword = IntentionKeyword(
  178. id=str(uuid.uuid4()),
  179. intention_id=intention_id,
  180. name=name,
  181. created_by=current_user.id,
  182. created_at=datetime.now(),
  183. )
  184. db.session.add(intention_keyword)
  185. db.session.commit()
  186. return intention_keyword
  187. @staticmethod
  188. def update_intention_keyword(intention_keyword_id: str, args: dict) -> IntentionKeyword:
  189. intention_keyword = IntentionKeywordService.get_intention_keyword(intention_keyword_id)
  190. if not intention_keyword:
  191. raise NotFound("IntentionKeyword not found")
  192. name = args["name"]
  193. intention_keyword_new = (
  194. IntentionKeyword.query.filter(
  195. IntentionKeyword.id != intention_keyword.id,
  196. IntentionKeyword.name == name)
  197. .first()
  198. )
  199. if intention_keyword_new:
  200. raise IntentionKeywordNameDuplicateError(f"IntentionKeyword with name {name} already exists.")
  201. intention_keyword.name = name
  202. intention_id = args["intention_id"]
  203. intention = IntentionService.get_intention(intention_id)
  204. if not intention:
  205. raise NotFound("Intention not found")
  206. intention_keyword.intention_id = intention_id
  207. intention_keyword.updated_by = current_user.id
  208. intention_keyword.updated_at = datetime.now()
  209. db.session.add(intention_keyword)
  210. db.session.commit()
  211. return intention_keyword
  212. @staticmethod
  213. def delete_intention_keyword(intention_keyword_id: str):
  214. intention_keyword = IntentionKeywordService.get_intention_keyword(intention_keyword_id)
  215. if not intention_keyword:
  216. raise NotFound("IntentionKeyword not found")
  217. db.session.delete(intention_keyword)
  218. db.session.commit()
  219. @staticmethod
  220. def delete_intention_keywords(intention_keyword_ids: list[str]):
  221. intention_keywords = IntentionKeyword.query.filter(IntentionKeyword.id.in_(intention_keyword_ids)).all()
  222. for intention_keyword in intention_keywords:
  223. db.session.delete(intention_keyword)
  224. db.session.commit()
  225. @staticmethod
  226. def delete_intention_keywords_by_intention_id(intention_id: str):
  227. intention_keywords = IntentionKeyword.query.filter(IntentionKeyword.intention_id == intention_id).all()
  228. for intention_keyword in intention_keywords:
  229. db.session.delete(intention_keyword)
  230. db.session.commit()
  231. @staticmethod
  232. def get_intention_keyword(intention_keyword_id: str) -> Optional[IntentionKeyword]:
  233. intention_keyword: Optional[IntentionKeyword] = (
  234. IntentionKeyword.query.filter_by(id=intention_keyword_id).first()
  235. )
  236. return intention_keyword
  237. @staticmethod
  238. def get_intention_keyword_by_name(intention_id, name: str) -> Optional[IntentionKeyword]:
  239. intention_keyword: Optional[IntentionKeyword] = (
  240. IntentionKeyword.query.filter(
  241. IntentionKeyword.intention_id == intention_id,
  242. IntentionKeyword.name == name,
  243. ).first()
  244. )
  245. return intention_keyword
  246. class IntentionCorpusService:
  247. @staticmethod
  248. def get_intention_corpus(corpus_id: str) -> Optional[IntentionCorpus]:
  249. intention_corpus: Optional[IntentionCorpus] = (
  250. IntentionCorpus.query.filter(IntentionCorpus.id == corpus_id).first()
  251. )
  252. return intention_corpus
  253. @staticmethod
  254. def get_page_intention_corpus(page, per_page, search=None, intention_id=None):
  255. query = IntentionCorpus.query.order_by(IntentionCorpus.created_at.desc())
  256. if search:
  257. query = query.filter(IntentionCorpus.question.like(f"%{search}%"))
  258. if intention_id:
  259. query = query.filter(IntentionCorpus.intention_id == intention_id)
  260. intention_corpus = query.paginate(page=page, per_page=per_page, error_out=False)
  261. return intention_corpus.items, intention_corpus.total
  262. @staticmethod
  263. def get_intention_corpus_by_question(question: str) -> Optional[IntentionCorpus]:
  264. intention_corpus: Optional[IntentionCorpus] = (
  265. IntentionCorpus.query.filter(IntentionCorpus.question == question).first()
  266. )
  267. return intention_corpus
  268. @staticmethod
  269. def save_intention_corpus(args: dict):
  270. question = args["question"]
  271. intention_corpus = IntentionCorpusService.get_intention_corpus_by_question(question)
  272. if intention_corpus:
  273. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  274. intention_id = args["intention_id"]
  275. intention = IntentionService.get_intention(intention_id)
  276. if not intention:
  277. raise NotFound(f"Intention with id {intention_id} not found")
  278. intention_corpus = IntentionCorpus(
  279. id=str(uuid.uuid4()),
  280. question=question,
  281. intention_id=intention_id,
  282. created_by=current_user.id,
  283. created_at=datetime.now(),
  284. )
  285. if "question_config" in args:
  286. intention_corpus.question_config = args["question_config"]
  287. db.session.add(intention_corpus)
  288. db.session.commit()
  289. return intention_corpus
  290. @staticmethod
  291. def update_intention_corpus(corpus_id: str, args: dict):
  292. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  293. if not intention_corpus:
  294. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  295. if "question" in args:
  296. question = args["question"]
  297. intention_corpus_new = (
  298. IntentionCorpus.query.filter(
  299. IntentionCorpus.id != corpus_id,
  300. IntentionCorpus.question == question
  301. ).first()
  302. )
  303. if intention_corpus_new:
  304. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  305. intention_corpus.question = question
  306. if "question_config" in args:
  307. intention_corpus.question_config = args["question_config"]
  308. if "intention_id" in args:
  309. intention_id = args["intention_id"]
  310. intention = IntentionService.get_intention(intention_id)
  311. if not intention:
  312. raise NotFound(f"Intention with id {intention_id} not found")
  313. intention_corpus.intention_id = intention.id
  314. intention_corpus.updated_at = datetime.now()
  315. intention_corpus.updated_by = current_user.id
  316. db.session.add(intention_corpus)
  317. db.session.commit()
  318. return intention_corpus
  319. @staticmethod
  320. def delete_intention_corpus_by_id(corpus_id: str):
  321. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  322. if not intention_corpus:
  323. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  324. IntentionCorpusService.delete_intention_corpus(intention_corpus)
  325. @staticmethod
  326. def delete_intention_corpus(intention_corpus: IntentionCorpus):
  327. similarity_questions = intention_corpus.similarity_questions
  328. if similarity_questions:
  329. raise Forbidden(f"存在与其关联的相似问题,无法删除Id为{intention_corpus.id}训练语料")
  330. db.session.delete(intention_corpus)
  331. db.session.commit()
  332. class IntentionCorpusSimilarityQuestionService:
  333. @staticmethod
  334. def save_similarity_question(corpus_id: str, args: dict):
  335. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  336. if not intention_corpus:
  337. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  338. question = args["question"]
  339. intention_corpus_similarity_question = (
  340. IntentionCorpusSimilarityQuestionService.get_similarity_question_by_question(question)
  341. )
  342. if intention_corpus_similarity_question:
  343. raise IntentionCorpusQuestionDuplicateError(f"IntentionCorpus with question {question} already exists.")
  344. intention_corpus_similarity_question = IntentionCorpusSimilarityQuestion(
  345. id=str(uuid.uuid4()),
  346. question=question,
  347. corpus_id=corpus_id,
  348. created_by=current_user.id,
  349. created_at=datetime.now(),
  350. )
  351. if "question_config" in args:
  352. intention_corpus_similarity_question.question_config = args["question_config"]
  353. db.session.add(intention_corpus_similarity_question)
  354. db.session.commit()
  355. return intention_corpus_similarity_question
  356. @staticmethod
  357. def update_similarity_question(similarity_question_id: str, args: dict):
  358. similarity_question = IntentionCorpusSimilarityQuestionService.get_similarity_question(similarity_question_id)
  359. if not similarity_question:
  360. raise NotFound(f"IntentionCorpus with id {similarity_question_id} not found")
  361. if "corpus_id" in args:
  362. corpus_id = args["corpus_id"]
  363. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  364. if not intention_corpus:
  365. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  366. similarity_question.corpus_id = corpus_id
  367. if "question" in args:
  368. similarity_question.question = args["question"]
  369. if "question_config" in args:
  370. similarity_question.question_config = args["question_config"]
  371. db.session.add(similarity_question)
  372. db.session.commit()
  373. return similarity_question
  374. @staticmethod
  375. def get_similarity_question(similarity_question_id: str) -> Optional[IntentionCorpusSimilarityQuestion]:
  376. similarity_question: Optional[IntentionCorpus] = (
  377. IntentionCorpusSimilarityQuestion.query.filter_by(id=similarity_question_id).first()
  378. )
  379. return similarity_question
  380. @staticmethod
  381. def get_similarity_question_by_question(question: str) -> Optional[IntentionCorpusSimilarityQuestion]:
  382. similarity_question: Optional[IntentionCorpusSimilarityQuestion] = (
  383. IntentionCorpusSimilarityQuestion.query.filter_by(question=question).first()
  384. )
  385. return similarity_question
  386. @staticmethod
  387. def get_similarity_questions_by_corpus_id_like_question(corpus_id, search = None):
  388. query = (
  389. IntentionCorpusSimilarityQuestion.query
  390. .filter(IntentionCorpusSimilarityQuestion.corpus_id==corpus_id)
  391. .order_by(IntentionCorpusSimilarityQuestion.created_at.desc())
  392. )
  393. if search:
  394. query = query.filter(IntentionCorpusSimilarityQuestion.question.ilike(f"%{search}%"))
  395. similarity_questions = query.all()
  396. return similarity_questions
  397. @staticmethod
  398. def delete_similarity_question_by_corpus_id(corpus_id: str):
  399. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  400. if not intention_corpus:
  401. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  402. logging.info(intention_corpus.similarity_questions)
  403. IntentionCorpusSimilarityQuestionService.delete_similarity_questions(intention_corpus.similarity_questions)
  404. @staticmethod
  405. def delete_similarity_question_by_id(similarity_question_id: str):
  406. similarity_question = IntentionCorpusSimilarityQuestionService.get_similarity_question(similarity_question_id)
  407. if not similarity_question:
  408. raise NotFound(f"IntentionCorpus with id {similarity_question_id} not found")
  409. IntentionCorpusSimilarityQuestionService.delete_similarity_question(similarity_question)
  410. @staticmethod
  411. def delete_similarity_question(similarity_question: IntentionCorpusSimilarityQuestion):
  412. db.session.delete(similarity_question)
  413. db.session.commit()
  414. @staticmethod
  415. def delete_similarity_questions_by_ids(similarity_question_ids: list[str]):
  416. similarity_questions = (
  417. IntentionCorpusSimilarityQuestion.query
  418. .filter(IntentionCorpusSimilarityQuestion.id.in_(similarity_question_ids))
  419. .all()
  420. )
  421. IntentionCorpusSimilarityQuestionService.delete_similarity_questions(similarity_questions)
  422. @staticmethod
  423. def delete_similarity_questions(similarity_questions: list[IntentionCorpusSimilarityQuestion]):
  424. if not similarity_questions:
  425. return
  426. for similarity_question in similarity_questions:
  427. db.session.delete(similarity_question)
  428. db.session.commit()
  429. class IntentionTrainTaskService:
  430. @staticmethod
  431. def get_page_intention_train_tasks(page, per_page, search=None):
  432. query = (
  433. IntentionTrainTask.query.order_by(IntentionTrainTask.created_at.desc())
  434. )
  435. if search:
  436. query = query.filter(IntentionTrainTask.name.ilike(f"%{search}%"))
  437. intention_train_tasks = query.paginate(page=page, per_page=per_page, error_out=False)
  438. return intention_train_tasks.items, intention_train_tasks.total
  439. @staticmethod
  440. def get_train_task(train_task_id: str) -> Optional[IntentionTrainTask]:
  441. train_task: Optional[IntentionTrainTask] = (
  442. IntentionTrainTask.query.filter_by(id=train_task_id).first()
  443. )
  444. return train_task
  445. @staticmethod
  446. def save_train_task(args: dict):
  447. train_task = IntentionTrainTask(
  448. id=str(uuid.uuid4()),
  449. name=args["name"],
  450. status=args["status"],
  451. created_by=current_user.id,
  452. created_at=datetime.now(),
  453. )
  454. db.session.add(train_task)
  455. db.session.commit()
  456. return train_task
  457. @staticmethod
  458. def update_train_task(task_id: str, args: dict):
  459. train_task = IntentionTrainTaskService.get_train_task(task_id)
  460. if not train_task:
  461. raise NotFound(f"IntentionTrainTask with id {task_id} not found")
  462. if "name" in args:
  463. train_task.name = args["name"]
  464. if "status" in args:
  465. train_task.status = args["status"]
  466. db.session.add(train_task)
  467. db.session.commit()
  468. return train_task
  469. class IntentionTrainFileService:
  470. @staticmethod
  471. def get_train_file(name: str, version: str, type: str) -> Optional[IntentionTrainFile]:
  472. train_file = (
  473. IntentionTrainFile.query
  474. .filter_by(
  475. name=name,
  476. version=version,
  477. type=type,
  478. )
  479. .first()
  480. )
  481. return train_file
  482. @staticmethod
  483. def get_train_files(name=None, version=None, type=None):
  484. query = IntentionTrainFile.query.order_by(IntentionTrainFile.created_at.desc())
  485. if name:
  486. query = query.filter_by(name=name)
  487. if version:
  488. query = query.filter_by(version=version)
  489. if type:
  490. query = query.filter_by(type=type)
  491. train_files = query.all()
  492. return train_files
  493. @staticmethod
  494. def save_train_file(args: dict):
  495. name = args["name"]
  496. version = args["version"]
  497. type = args["type"]
  498. train_file = IntentionTrainFileService.get_train_file(name, version, type)
  499. if train_file:
  500. raise IntentionTrainFileDuplicateError(f"IntentionTrainFile with name-version-type "
  501. f"{name}-{version}-{type} already exists.")
  502. intention_train_file = IntentionTrainFile(
  503. id=str(uuid.uuid4()),
  504. name=name,
  505. version=version,
  506. type=type,
  507. data_source_type=args["data_source_type"],
  508. data_source_info=args["data_source_info"],
  509. created_by=current_user.id,
  510. created_at=datetime.now(),
  511. )
  512. db.session.add(intention_train_file)
  513. db.session.commit()
  514. return intention_train_file
  515. class IntentionTrainFileBindingService:
  516. @staticmethod
  517. def save_train_file_binding(args: dict):
  518. file_id = args["file_id"]
  519. task_id = args["task_id"]
  520. train_file_binding = IntentionTrainFileBinding(
  521. id=str(uuid.uuid4()),
  522. file_id=file_id,
  523. task_id=task_id,
  524. )
  525. db.session.add(train_file_binding)
  526. db.session.commit()
  527. return train_file_binding