intention.py 17 KB

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