intention.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. import logging
  2. from flask import request
  3. from flask_restful import Resource, marshal, marshal_with, reqparse
  4. from werkzeug.exceptions import Forbidden, NotFound
  5. from controllers.console import api
  6. from controllers.console.wraps import account_initialization_required, setup_required
  7. from fields.intention_fields import (
  8. intention_corpus_detail_fields,
  9. intention_corpus_similarity_question_fields,
  10. intention_detail_fields,
  11. intention_keyword_detail_fields,
  12. intention_keyword_fields,
  13. intention_page_fields,
  14. intention_type_detail_fields,
  15. intention_type_page_fields,
  16. )
  17. from libs.login import login_required
  18. from services.intention_service import (
  19. IntentionCorpusService,
  20. IntentionCorpusSimilarityQuestionService,
  21. IntentionKeywordService,
  22. IntentionService,
  23. IntentionTypeService,
  24. )
  25. class IntentionListApi(Resource):
  26. @setup_required
  27. @login_required
  28. @account_initialization_required
  29. def get(self):
  30. page = request.args.get("page", default=1, type=int)
  31. limit = request.args.get("limit", default=20, type=int)
  32. type_id = request.args.get("type_id", default=None, type=str)
  33. name_search = request.args.get("name_search", default=None, type=str)
  34. intentions, total = IntentionService.get_intentions(page, limit, type_id, name_search)
  35. data = marshal(intentions, intention_page_fields)
  36. response = {"data": data, "has_more": len(intentions) == limit, "limit": limit,
  37. "total": total, "page": page}
  38. return response, 200
  39. @setup_required
  40. @login_required
  41. @account_initialization_required
  42. def post(self):
  43. parser = reqparse.RequestParser()
  44. parser.add_argument(
  45. "name",
  46. nullable=False,
  47. required=True,
  48. help="type is required. Name must be between 1 to 40 characters.",
  49. )
  50. parser.add_argument(
  51. "type_id",
  52. nullable=False,
  53. required=True,
  54. help="type is required.",
  55. )
  56. args = parser.parse_args()
  57. intention = IntentionService.save_intention(args)
  58. response = marshal(intention, intention_detail_fields)
  59. return response, 200
  60. class IntentionApi(Resource):
  61. @setup_required
  62. @login_required
  63. @account_initialization_required
  64. def get(self, intention_id):
  65. intention = IntentionService.get_intention(intention_id)
  66. return marshal(intention, intention_detail_fields)
  67. @setup_required
  68. @login_required
  69. @account_initialization_required
  70. def patch(self, intention_id):
  71. parser = reqparse.RequestParser()
  72. parser.add_argument(
  73. "name",
  74. nullable=False,
  75. required=True,
  76. help="type is required. Name must be between 1 to 40 characters.",
  77. )
  78. parser.add_argument(
  79. "type_id",
  80. nullable=False,
  81. required=True,
  82. help="type is required.",
  83. )
  84. args = parser.parse_args()
  85. intention = IntentionService.update_intention(intention_id, args)
  86. response = marshal(intention, intention_detail_fields)
  87. return response, 200
  88. @setup_required
  89. @login_required
  90. @account_initialization_required
  91. def delete(self, intention_id):
  92. IntentionService.delete_intention(intention_id)
  93. return 200
  94. class IntentionTypeListApi(Resource):
  95. @setup_required
  96. @login_required
  97. @account_initialization_required
  98. def get(self):
  99. page = request.args.get("page", default=1, type=int)
  100. limit = request.args.get("limit", default=20, type=int)
  101. search = request.args.get("search", default=None, type=str)
  102. intention_types, total = IntentionTypeService.get_intention_types(page, limit, search)
  103. data = marshal(intention_types, intention_type_page_fields)
  104. response = {"data": data, "has_more": len(intention_types) == limit, "limit": limit,
  105. "total": total, "page": page}
  106. return response, 200
  107. @setup_required
  108. @login_required
  109. @account_initialization_required
  110. def post(self):
  111. parser = reqparse.RequestParser()
  112. parser.add_argument(
  113. "name",
  114. nullable=False,
  115. required=True,
  116. help="type is required. Name must be between 1 to 40 characters.",
  117. )
  118. args = parser.parse_args()
  119. intention_type = IntentionTypeService.save_intention_type(args)
  120. response = marshal(intention_type, intention_type_detail_fields)
  121. return response, 200
  122. class IntentionTypeApi(Resource):
  123. @setup_required
  124. @login_required
  125. @account_initialization_required
  126. def get(self, intention_type_id):
  127. intention_type = IntentionTypeService.get_intention_type(intention_type_id)
  128. return marshal(intention_type, intention_type_detail_fields)
  129. @setup_required
  130. @login_required
  131. @account_initialization_required
  132. def patch(self, intention_type_id):
  133. parser = reqparse.RequestParser()
  134. parser.add_argument(
  135. "name",
  136. nullable=False,
  137. required=True,
  138. help="type is required. Name must be between 1 to 40 characters.",
  139. )
  140. args = parser.parse_args()
  141. intention_type = IntentionTypeService.update_intention_type(intention_type_id, args)
  142. return marshal(intention_type, intention_type_detail_fields), 200
  143. @setup_required
  144. @login_required
  145. @account_initialization_required
  146. def delete(self, intention_type_id):
  147. IntentionTypeService.delete_intention_type(intention_type_id)
  148. return 200
  149. class IntentionKeywordListApi(Resource):
  150. @setup_required
  151. @login_required
  152. @account_initialization_required
  153. @marshal_with(intention_keyword_fields)
  154. def get(self, intention_id):
  155. search = request.args.get("search", default=None, type=str)
  156. intention = IntentionService.get_intention(intention_id)
  157. if not intention:
  158. raise NotFound("Intention not found")
  159. intention_keywords = IntentionKeywordService.get_intention_keywords(intention_id, search)
  160. return intention_keywords, 200
  161. @setup_required
  162. @login_required
  163. @account_initialization_required
  164. @marshal_with(intention_keyword_detail_fields)
  165. def post(self, intention_id):
  166. parser = reqparse.RequestParser()
  167. parser.add_argument(
  168. "name",
  169. nullable=False,
  170. required=True,
  171. help="type is required. Name must be between 1 to 40 characters.",
  172. )
  173. args = parser.parse_args()
  174. intention = IntentionService.get_intention(intention_id)
  175. if not intention:
  176. raise NotFound("Intention not found")
  177. intention_keyword = IntentionKeywordService.save_intention_keyword(intention_id, args)
  178. return intention_keyword, 200
  179. @setup_required
  180. @login_required
  181. @account_initialization_required
  182. def delete(self, intention_id):
  183. intention = IntentionService.get_intention(intention_id)
  184. if not intention:
  185. raise NotFound("Intention not found")
  186. IntentionKeywordService.delete_intention_keywords_by_intention_id(intention_id)
  187. return 200
  188. class IntentionKeywordApi(Resource):
  189. @setup_required
  190. @login_required
  191. @account_initialization_required
  192. def get(self, intention_keyword_id):
  193. intention_keyword = IntentionKeywordService.get_intention_keyword(intention_keyword_id)
  194. if not intention_keyword:
  195. return {}, 200
  196. return marshal(intention_keyword, intention_keyword_detail_fields), 200
  197. @setup_required
  198. @login_required
  199. @account_initialization_required
  200. @marshal_with(intention_keyword_detail_fields)
  201. def patch(self, intention_keyword_id):
  202. parser = reqparse.RequestParser()
  203. parser.add_argument(
  204. "name",
  205. nullable=False,
  206. required=True,
  207. help="type is required. Name must be between 1 to 40 characters.",
  208. )
  209. parser.add_argument(
  210. "intention_id",
  211. nullable=False,
  212. required=True,
  213. help="type is required.",
  214. )
  215. args = parser.parse_args()
  216. intention_keyword = IntentionKeywordService.update_intention_keyword(intention_keyword_id, args)
  217. return intention_keyword, 200
  218. @setup_required
  219. @login_required
  220. @account_initialization_required
  221. def delete(self, intention_keyword_id):
  222. IntentionKeywordService.delete_intention_keyword(intention_keyword_id)
  223. return 200
  224. class IntentionKeywordBatchApi(Resource):
  225. @setup_required
  226. @login_required
  227. @account_initialization_required
  228. def post(self):
  229. parser = reqparse.RequestParser()
  230. parser.add_argument(
  231. "method",
  232. nullable=False,
  233. required=True,
  234. help="method is required.",
  235. choices=["create", "update", "delete"],
  236. type=str,
  237. location="json",
  238. )
  239. parser.add_argument(
  240. "delete_data",
  241. nullable=False,
  242. required=True,
  243. help="delete_data is required.",
  244. type=list,
  245. location="json",
  246. )
  247. args = parser.parse_args()
  248. logging.info(args)
  249. method = args["method"]
  250. if method == "delete":
  251. intention_keyword_ids = args["delete_data"]
  252. IntentionKeywordService.delete_intention_keywords(intention_keyword_ids)
  253. return 200
  254. else:
  255. raise NotFound(f"method with name {method} not found")
  256. class IntentionCorpusListApi(Resource):
  257. @setup_required
  258. @login_required
  259. @account_initialization_required
  260. def get(self):
  261. page = request.args.get("page", default=1, type=int)
  262. limit = request.args.get("limit", default=20, type=int)
  263. question_search = request.args.get("question_search", default=None, type=str)
  264. intention_id = request.args.get("intention_id", default=None, type=str)
  265. intention_corpus, total = IntentionCorpusService.get_page_intention_corpus(
  266. page, limit, question_search, intention_id)
  267. data = marshal(intention_corpus, intention_corpus_detail_fields)
  268. response = {"data": data, "has_more": len(intention_corpus) == limit, "limit": limit,
  269. "total": total, "page": page}
  270. return response, 200
  271. @setup_required
  272. @login_required
  273. @account_initialization_required
  274. def post(self):
  275. parser = reqparse.RequestParser()
  276. parser.add_argument(
  277. "question",
  278. nullable=False,
  279. required=True,
  280. help="type is required. Question must be between 1 to 40 characters.",
  281. )
  282. parser.add_argument(
  283. "question_config",
  284. nullable=True,
  285. required=False,
  286. location="json",
  287. )
  288. parser.add_argument(
  289. "intention_id",
  290. nullable=False,
  291. required=True,
  292. help="type is required.",
  293. )
  294. args = parser.parse_args()
  295. intention_corpus = IntentionCorpusService.save_intention_corpus(args)
  296. return marshal(intention_corpus, intention_corpus_detail_fields), 200
  297. class IntentionCorpusApi(Resource):
  298. @setup_required
  299. @login_required
  300. @account_initialization_required
  301. def get(self, corpus_id):
  302. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  303. if not intention_corpus:
  304. raise NotFound(f"IntentionCorpus with id {corpus_id} not found")
  305. return marshal(intention_corpus, intention_corpus_detail_fields), 200
  306. @setup_required
  307. @login_required
  308. @account_initialization_required
  309. def patch(self, corpus_id):
  310. parser = reqparse.RequestParser()
  311. parser.add_argument(
  312. "question",
  313. nullable=True,
  314. required=False,
  315. type=str,
  316. location="json",
  317. )
  318. parser.add_argument(
  319. "question_config",
  320. nullable=True,
  321. required=False,
  322. location="json",
  323. )
  324. parser.add_argument(
  325. "intention_id",
  326. nullable=True,
  327. required=False,
  328. type=str,
  329. location="json",
  330. )
  331. args = parser.parse_args()
  332. intention_corpus = IntentionCorpusService.update_intention_corpus(corpus_id, args)
  333. return marshal(intention_corpus, intention_corpus_detail_fields), 200
  334. @setup_required
  335. @login_required
  336. @account_initialization_required
  337. def delete(self, corpus_id):
  338. intention_corpus = IntentionCorpusService.get_intention_corpus(corpus_id)
  339. if not intention_corpus:
  340. raise NotFound(f"未发现Id未{corpus_id}的训练语料")
  341. similarity_questions = intention_corpus.similarity_questions
  342. if similarity_questions:
  343. raise Forbidden(f"存在与其关联的相似问题,无法删除Id为{corpus_id}训练语料")
  344. IntentionCorpusService.delete_intention_corpus(intention_corpus)
  345. return 200
  346. class IntentionCorpusSimilarityQuestionApi(Resource):
  347. @setup_required
  348. @login_required
  349. @account_initialization_required
  350. def get(self, corpus_id):
  351. search = request.args.get("search", default=None, type=str)
  352. similarity_questions = (
  353. IntentionCorpusSimilarityQuestionService
  354. .get_similarity_questions_by_corpus_id_like_question(corpus_id, search)
  355. )
  356. return marshal(similarity_questions, intention_corpus_similarity_question_fields), 200
  357. @setup_required
  358. @login_required
  359. @account_initialization_required
  360. def post(self, corpus_id):
  361. parser = reqparse.RequestParser()
  362. parser.add_argument(
  363. "question",
  364. nullable=False,
  365. required=True,
  366. help="type is required. Question must be between 1 to 40 characters.",
  367. location="json",
  368. )
  369. parser.add_argument(
  370. "question_config",
  371. nullable=True,
  372. required=False,
  373. location="json",
  374. )
  375. args = parser.parse_args()
  376. intention_corpus_similarity_question = (
  377. IntentionCorpusSimilarityQuestionService.save_similarity_question(corpus_id, args)
  378. )
  379. return marshal(intention_corpus_similarity_question, intention_corpus_similarity_question_fields), 200
  380. @setup_required
  381. @login_required
  382. @account_initialization_required
  383. def delete(self, corpus_id):
  384. IntentionCorpusSimilarityQuestionService.delete_similarity_question_by_corpus_id(corpus_id)
  385. return 200
  386. class IntentionCorpusSimilarityQuestionUpdateAndDeleteApi(Resource):
  387. @setup_required
  388. @login_required
  389. @account_initialization_required
  390. def patch(self, similarity_question_id):
  391. parser = reqparse.RequestParser()
  392. parser.add_argument(
  393. "question",
  394. nullable=True,
  395. required=False,
  396. help="type is required. Question must be between 1 to 40 characters.",
  397. location="json",
  398. )
  399. parser.add_argument(
  400. "question_config",
  401. nullable=True,
  402. required=False,
  403. location="json",
  404. )
  405. parser.add_argument(
  406. "corpus_id",
  407. nullable=True,
  408. required=False,
  409. location="json",
  410. )
  411. args = parser.parse_args()
  412. similarity_question = (
  413. IntentionCorpusSimilarityQuestionService.update_similarity_question(similarity_question_id, args)
  414. )
  415. return marshal(similarity_question, intention_corpus_similarity_question_fields), 200
  416. @setup_required
  417. @login_required
  418. @account_initialization_required
  419. def delete(self, similarity_question_id):
  420. IntentionCorpusSimilarityQuestionService.delete_similarity_question_by_id(similarity_question_id)
  421. return 200
  422. class IntentionCorpusSimilarityQuestionBatchApi(Resource):
  423. @setup_required
  424. @login_required
  425. @account_initialization_required
  426. def post(self):
  427. parser = reqparse.RequestParser()
  428. parser.add_argument(
  429. "method",
  430. nullable=False,
  431. required=True,
  432. help="method is required.",
  433. choices=["create", "update", "delete"],
  434. type=str,
  435. location="json",
  436. )
  437. parser.add_argument(
  438. "data",
  439. nullable=False,
  440. required=True,
  441. help="data is required.",
  442. type=list,
  443. location="json",
  444. )
  445. args = parser.parse_args()
  446. logging.info(args)
  447. method = args["method"]
  448. if method == "delete":
  449. similarity_question_ids = args["data"]
  450. IntentionCorpusSimilarityQuestionService.delete_similarity_questions_by_ids(similarity_question_ids)
  451. return 200
  452. else:
  453. raise NotFound(f"method with name {method} not found")
  454. api.add_resource(IntentionListApi, "/intentions")
  455. api.add_resource(IntentionApi, "/intentions/<uuid:intention_id>")
  456. api.add_resource(IntentionTypeListApi, "/intentions/types")
  457. api.add_resource(IntentionTypeApi, "/intentions/types/<uuid:intention_type_id>")
  458. api.add_resource(IntentionKeywordListApi, "/intentions/<uuid:intention_id>/keywords")
  459. api.add_resource(IntentionKeywordApi, "/intentions/keywords/<uuid:intention_keyword_id>")
  460. api.add_resource(IntentionKeywordBatchApi, "/intentions/keywords/batch")
  461. api.add_resource(IntentionCorpusListApi, "/intentions/corpus")
  462. api.add_resource(IntentionCorpusApi, "/intentions/corpus/<uuid:corpus_id>")
  463. api.add_resource(IntentionCorpusSimilarityQuestionApi, "/intentions/corpus/<uuid:corpus_id>/similarity_questions")
  464. api.add_resource(IntentionCorpusSimilarityQuestionUpdateAndDeleteApi,
  465. "/intentions/similarity_questions/<uuid:similarity_question_id>")
  466. api.add_resource(IntentionCorpusSimilarityQuestionBatchApi, "/intentions/similarity_questions/batch")