intention.py 18 KB

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