api_server.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # vim:fenc=utf-8
  4. import time
  5. import logging
  6. import werkzeug.exceptions
  7. from flask import Flask, request, jsonify
  8. from argparse import ArgumentParser
  9. from pqai_agent import configs
  10. from pqai_agent import logging_service, chat_service, prompt_templates
  11. from pqai_agent.history_dialogue_service import HistoryDialogueService
  12. from pqai_agent.user_manager import MySQLUserManager, MySQLUserRelationManager
  13. from pqai_agent_server.utils import wrap_response
  14. from pqai_agent_server.utils import (
  15. run_extractor_prompt,
  16. run_chat_prompt,
  17. run_response_type_prompt,
  18. )
  19. app = Flask('agent_api_server')
  20. logger = logging_service.logger
  21. @app.route('/api/listStaffs', methods=['GET'])
  22. def list_staffs():
  23. staff_data = app.user_relation_manager.list_staffs()
  24. return wrap_response(200, data=staff_data)
  25. @app.route('/api/getStaffProfile', methods=['GET'])
  26. def get_staff_profile():
  27. staff_id = request.args['staff_id']
  28. profile = app.user_manager.get_staff_profile(staff_id)
  29. if not profile:
  30. return wrap_response(404, msg='staff not found')
  31. else:
  32. return wrap_response(200, data=profile)
  33. @app.route('/api/getUserProfile', methods=['GET'])
  34. def get_user_profile():
  35. user_id = request.args['user_id']
  36. profile = app.user_manager.get_user_profile(user_id)
  37. if not profile:
  38. resp = {
  39. 'code': 404,
  40. 'msg': 'user not found'
  41. }
  42. else:
  43. resp = {
  44. 'code': 200,
  45. 'msg': 'success',
  46. 'data': profile
  47. }
  48. return jsonify(resp)
  49. @app.route('/api/listUsers', methods=['GET'])
  50. def list_users():
  51. user_name = request.args.get('user_name', None)
  52. user_union_id = request.args.get('user_union_id', None)
  53. if not user_name and not user_union_id:
  54. resp = {
  55. 'code': 400,
  56. 'msg': 'user_name or user_union_id is required'
  57. }
  58. return jsonify(resp)
  59. data = app.user_manager.list_users(user_name=user_name, user_union_id=user_union_id)
  60. return jsonify({'code': 200, 'data': data})
  61. @app.route('/api/getDialogueHistory', methods=['GET'])
  62. def get_dialogue_history():
  63. staff_id = request.args['staff_id']
  64. user_id = request.args['user_id']
  65. recent_minutes = int(request.args.get('recent_minutes', 1440))
  66. dialogue_history = app.history_dialogue_service.get_dialogue_history(staff_id, user_id, recent_minutes)
  67. return jsonify({'code': 200, 'data': dialogue_history})
  68. @app.route('/api/listModels', methods=['GET'])
  69. def list_models():
  70. models = [
  71. {
  72. 'model_type': 'openai_compatible',
  73. 'model_name': chat_service.VOLCENGINE_MODEL_DEEPSEEK_V3,
  74. 'display_name': 'DeepSeek V3 on 火山',
  75. },
  76. {
  77. 'model_type': 'openai_compatible',
  78. 'model_name': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_32K,
  79. 'display_name': '豆包Pro 32K',
  80. },
  81. {
  82. 'model_type': 'openai_compatible',
  83. 'model_name': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_1_5,
  84. 'display_name': '豆包Pro 1.5',
  85. },
  86. {
  87. 'model_type': 'openai_compatible',
  88. 'model_name': chat_service.VOLCENGINE_BOT_DEEPSEEK_V3_SEARCH,
  89. 'display_name': 'DeepSeek V3联网 on 火山',
  90. },
  91. {
  92. 'model_type': 'openai_compatible',
  93. 'model_name': chat_service.VOLCENGINE_MODEL_DOUBAO_1_5_VISION_PRO,
  94. 'display_name': '豆包1.5视觉理解Pro',
  95. },
  96. ]
  97. return wrap_response(200, data=models)
  98. @app.route('/api/listScenes', methods=['GET'])
  99. def list_scenes():
  100. scenes = [
  101. {'scene': 'greeting', 'display_name': '问候'},
  102. {'scene': 'chitchat', 'display_name': '闲聊'},
  103. {'scene': 'profile_extractor', 'display_name': '画像提取'},
  104. {'scene': 'response_type_detector', 'display_name': '回复模态判断'},
  105. {'scene': 'custom_debugging', 'display_name': '自定义调试场景'}
  106. ]
  107. return wrap_response(200, data=scenes)
  108. @app.route('/api/getBasePrompt', methods=['GET'])
  109. def get_base_prompt():
  110. scene = request.args['scene']
  111. prompt_map = {
  112. 'greeting': prompt_templates.GENERAL_GREETING_PROMPT,
  113. 'chitchat': prompt_templates.CHITCHAT_PROMPT_COZE,
  114. 'profile_extractor': prompt_templates.USER_PROFILE_EXTRACT_PROMPT,
  115. 'response_type_detector': prompt_templates.RESPONSE_TYPE_DETECT_PROMPT,
  116. 'custom_debugging': '',
  117. }
  118. model_map = {
  119. 'greeting': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_32K,
  120. 'chitchat': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_32K,
  121. 'profile_extractor': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_1_5,
  122. 'response_type_detector': chat_service.VOLCENGINE_MODEL_DOUBAO_PRO_1_5,
  123. 'custom_debugging': chat_service.VOLCENGINE_BOT_DEEPSEEK_V3_SEARCH,
  124. }
  125. if scene not in prompt_map:
  126. return wrap_response(404, msg="scene not found")
  127. data = {
  128. 'model_name': model_map[scene],
  129. 'content': prompt_map[scene]
  130. }
  131. return wrap_response(200, data=data)
  132. @app.route('/api/runPrompt', methods=['POST'])
  133. def run_prompt():
  134. try:
  135. req_data = request.json
  136. logger.debug(req_data)
  137. scene = req_data['scene']
  138. if scene == 'profile_extractor':
  139. response = run_extractor_prompt(req_data)
  140. return wrap_response(200, data=response)
  141. elif scene == 'response_type_detector':
  142. response = run_response_type_prompt(req_data)
  143. return wrap_response(200, data=response.choices[0].message.content)
  144. else:
  145. response = run_chat_prompt(req_data)
  146. return wrap_response(200, data=response.choices[0].message.content)
  147. except Exception as e:
  148. logger.error(e)
  149. return wrap_response(500, msg='Error: {}'.format(e))
  150. @app.route("/api/healthCheck", methods=["GET"])
  151. def health_check():
  152. return wrap_response(200, msg="OK")
  153. @app.route("/api/getStaffSessionSummary", methods=["GET"])
  154. def get_staff_session_summary():
  155. staff_id = request.args.get("staff_id")
  156. status = request.args.get("status", 1)
  157. page_id = request.args.get("page_id", 1)
  158. page_size = request.args.get("page_size", 10)
  159. # check params
  160. try:
  161. page_id = int(page_id)
  162. page_size = int(page_size)
  163. status = int(status)
  164. except Exception as e:
  165. return wrap_response(404, msg="Invalid parameter: {}".format(e))
  166. staff_session_summary = app.user_manager.get_staff_sessions_summary_v1(
  167. staff_id, page_id, page_size, status
  168. )
  169. if not staff_session_summary:
  170. return wrap_response(404, msg="staff not found")
  171. else:
  172. return wrap_response(200, data=staff_session_summary)
  173. @app.route("/api/getStaffSessionList", methods=["GET"])
  174. def get_staff_session_list():
  175. staff_id = request.args.get("staff_id")
  176. if not staff_id:
  177. return wrap_response(404, msg="staff_id is required")
  178. page_size = request.args.get("page_size", 10)
  179. page_id = request.args.get("page_id", 1)
  180. staff_session_list = app.user_manager.get_staff_session_list_v1(staff_id, page_id, page_size)
  181. if not staff_session_list:
  182. return wrap_response(404, msg="staff not found")
  183. return wrap_response(200, data=staff_session_list)
  184. @app.route("/api/getStaffList", methods=["GET"])
  185. def get_staff_list():
  186. page_size = request.args.get("page_size", 10)
  187. page_id = request.args.get("page_id", 1)
  188. staff_list = app.user_manager.get_staff_list(page_id, page_size)
  189. if not staff_list:
  190. return wrap_response(404, msg="staff not found")
  191. return wrap_response(200, data=staff_list)
  192. @app.route("/api/getConversationList", methods=["GET"])
  193. def get_conversation_list():
  194. """
  195. 获取staff && customer的 私聊对话列表
  196. :return:
  197. """
  198. staff_id = request.args.get("staff_id")
  199. customer_id = request.args.get("customer_id")
  200. if not staff_id or not customer_id:
  201. return wrap_response(404, msg="staff_id and customer_id are required")
  202. page = request.args.get("page")
  203. response = app.user_manager.get_conversation_list_v1(staff_id, customer_id, page)
  204. return wrap_response(200, data=response)
  205. @app.route("/api/sendMessage", methods=["POST"])
  206. def send_message():
  207. return wrap_response(200, msg="暂不实现功能")
  208. @app.errorhandler(werkzeug.exceptions.BadRequest)
  209. def handle_bad_request(e):
  210. logger.error(e)
  211. return wrap_response(400, msg='Bad Request: {}'.format(e.description))
  212. if __name__ == "__main__":
  213. parser = ArgumentParser()
  214. parser.add_argument('--prod', action='store_true')
  215. parser.add_argument('--host', default='127.0.0.1')
  216. parser.add_argument('--port', type=int, default=8083)
  217. parser.add_argument('--log-level', default='INFO')
  218. args = parser.parse_args()
  219. config = configs.get()
  220. logging_level = logging.getLevelName(args.log_level)
  221. logging_service.setup_root_logger(level=logging_level, logfile_name='agent_api_server.log')
  222. user_db_config = config['storage']['user']
  223. staff_db_config = config['storage']['staff']
  224. user_manager = MySQLUserManager(
  225. user_db_config['mysql'], user_db_config['table'], staff_db_config['table']
  226. )
  227. app.user_manager = user_manager
  228. wecom_db_config = config['storage']['user_relation']
  229. user_relation_manager = MySQLUserRelationManager(
  230. user_db_config['mysql'],
  231. wecom_db_config['mysql'],
  232. config['storage']['staff']['table'],
  233. user_db_config['table'],
  234. wecom_db_config['table']['staff'],
  235. wecom_db_config['table']['relation'],
  236. wecom_db_config['table']['user'],
  237. )
  238. app.user_relation_manager = user_relation_manager
  239. app.history_dialogue_service = HistoryDialogueService(
  240. config['storage']['history_dialogue']['api_base_url']
  241. )
  242. app.run(debug=not args.prod, host=args.host, port=args.port)