You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bdunit.py 8.8KB

1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
1 jaar geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. # encoding:utf-8
  2. import json
  3. import os
  4. import uuid
  5. from uuid import getnode as get_mac
  6. import requests
  7. import plugins
  8. from bridge.context import ContextType
  9. from bridge.reply import Reply, ReplyType
  10. from common.log import logger
  11. from plugins import *
  12. """利用百度UNIT实现智能对话
  13. 如果命中意图,返回意图对应的回复,否则返回继续交付给下个插件处理
  14. """
  15. @plugins.register(
  16. name="BDunit",
  17. desire_priority=0,
  18. hidden=True,
  19. desc="Baidu unit bot system",
  20. version="0.1",
  21. author="jackson",
  22. )
  23. class BDunit(Plugin):
  24. def __init__(self):
  25. super().__init__()
  26. try:
  27. conf = super().load_config()
  28. if not conf:
  29. raise Exception("config.json not found")
  30. self.service_id = conf["service_id"]
  31. self.api_key = conf["api_key"]
  32. self.secret_key = conf["secret_key"]
  33. self.access_token = self.get_token()
  34. self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
  35. logger.info("[BDunit] inited")
  36. except Exception as e:
  37. logger.warn("[BDunit] init failed, ignore ")
  38. raise e
  39. def on_handle_context(self, e_context: EventContext):
  40. if e_context["context"].type != ContextType.TEXT:
  41. return
  42. content = e_context["context"].content
  43. logger.debug("[BDunit] on_handle_context. content: %s" % content)
  44. parsed = self.getUnit2(content)
  45. intent = self.getIntent(parsed)
  46. if intent: # 找到意图
  47. logger.debug("[BDunit] Baidu_AI Intent= %s", intent)
  48. reply = Reply()
  49. reply.type = ReplyType.TEXT
  50. reply.content = self.getSay(parsed)
  51. e_context["reply"] = reply
  52. e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
  53. else:
  54. e_context.action = EventAction.CONTINUE # 事件继续,交付给下个插件或默认逻辑
  55. def get_help_text(self, **kwargs):
  56. help_text = "本插件会处理询问实时日期时间,天气,数学运算等问题,这些技能由您的百度智能对话UNIT决定\n"
  57. return help_text
  58. def get_token(self):
  59. """获取访问百度UUNIT 的access_token
  60. #param api_key: UNIT apk_key
  61. #param secret_key: UNIT secret_key
  62. Returns:
  63. string: access_token
  64. """
  65. url = "https://aip.baidubce.com/oauth/2.0/token?client_id={}&client_secret={}&grant_type=client_credentials".format(self.api_key, self.secret_key)
  66. payload = ""
  67. headers = {"Content-Type": "application/json", "Accept": "application/json"}
  68. response = requests.request("POST", url, headers=headers, data=payload)
  69. # print(response.text)
  70. return response.json()["access_token"]
  71. def getUnit(self, query):
  72. """
  73. NLU 解析version 3.0
  74. :param query: 用户的指令字符串
  75. :returns: UNIT 解析结果。如果解析失败,返回 None
  76. """
  77. url = "https://aip.baidubce.com/rpc/2.0/unit/service/v3/chat?access_token=" + self.access_token
  78. request = {
  79. "query": query,
  80. "user_id": str(get_mac())[:32],
  81. "terminal_id": "88888",
  82. }
  83. body = {
  84. "log_id": str(uuid.uuid1()),
  85. "version": "3.0",
  86. "service_id": self.service_id,
  87. "session_id": str(uuid.uuid1()),
  88. "request": request,
  89. }
  90. try:
  91. headers = {"Content-Type": "application/json"}
  92. response = requests.post(url, json=body, headers=headers)
  93. return json.loads(response.text)
  94. except Exception:
  95. return None
  96. def getUnit2(self, query):
  97. """
  98. NLU 解析 version 2.0
  99. :param query: 用户的指令字符串
  100. :returns: UNIT 解析结果。如果解析失败,返回 None
  101. """
  102. url = "https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=" + self.access_token
  103. request = {"query": query, "user_id": str(get_mac())[:32]}
  104. body = {
  105. "log_id": str(uuid.uuid1()),
  106. "version": "2.0",
  107. "service_id": self.service_id,
  108. "session_id": str(uuid.uuid1()),
  109. "request": request,
  110. }
  111. try:
  112. headers = {"Content-Type": "application/json"}
  113. response = requests.post(url, json=body, headers=headers)
  114. return json.loads(response.text)
  115. except Exception:
  116. return None
  117. def getIntent(self, parsed):
  118. """
  119. 提取意图
  120. :param parsed: UNIT 解析结果
  121. :returns: 意图数组
  122. """
  123. if parsed and "result" in parsed and "response_list" in parsed["result"]:
  124. try:
  125. return parsed["result"]["response_list"][0]["schema"]["intent"]
  126. except Exception as e:
  127. logger.warning(e)
  128. return ""
  129. else:
  130. return ""
  131. def hasIntent(self, parsed, intent):
  132. """
  133. 判断是否包含某个意图
  134. :param parsed: UNIT 解析结果
  135. :param intent: 意图的名称
  136. :returns: True: 包含; False: 不包含
  137. """
  138. if parsed and "result" in parsed and "response_list" in parsed["result"]:
  139. response_list = parsed["result"]["response_list"]
  140. for response in response_list:
  141. if "schema" in response and "intent" in response["schema"] and response["schema"]["intent"] == intent:
  142. return True
  143. return False
  144. else:
  145. return False
  146. def getSlots(self, parsed, intent=""):
  147. """
  148. 提取某个意图的所有词槽
  149. :param parsed: UNIT 解析结果
  150. :param intent: 意图的名称
  151. :returns: 词槽列表。你可以通过 name 属性筛选词槽,
  152. 再通过 normalized_word 属性取出相应的值
  153. """
  154. if parsed and "result" in parsed and "response_list" in parsed["result"]:
  155. response_list = parsed["result"]["response_list"]
  156. if intent == "":
  157. try:
  158. return parsed["result"]["response_list"][0]["schema"]["slots"]
  159. except Exception as e:
  160. logger.warning(e)
  161. return []
  162. for response in response_list:
  163. if "schema" in response and "intent" in response["schema"] and "slots" in response["schema"] and response["schema"]["intent"] == intent:
  164. return response["schema"]["slots"]
  165. return []
  166. else:
  167. return []
  168. def getSlotWords(self, parsed, intent, name):
  169. """
  170. 找出命中某个词槽的内容
  171. :param parsed: UNIT 解析结果
  172. :param intent: 意图的名称
  173. :param name: 词槽名
  174. :returns: 命中该词槽的值的列表。
  175. """
  176. slots = self.getSlots(parsed, intent)
  177. words = []
  178. for slot in slots:
  179. if slot["name"] == name:
  180. words.append(slot["normalized_word"])
  181. return words
  182. def getSayByConfidence(self, parsed):
  183. """
  184. 提取 UNIT 置信度最高的回复文本
  185. :param parsed: UNIT 解析结果
  186. :returns: UNIT 的回复文本
  187. """
  188. if parsed and "result" in parsed and "response_list" in parsed["result"]:
  189. response_list = parsed["result"]["response_list"]
  190. answer = {}
  191. for response in response_list:
  192. if (
  193. "schema" in response
  194. and "intent_confidence" in response["schema"]
  195. and (not answer or response["schema"]["intent_confidence"] > answer["schema"]["intent_confidence"])
  196. ):
  197. answer = response
  198. return answer["action_list"][0]["say"]
  199. else:
  200. return ""
  201. def getSay(self, parsed, intent=""):
  202. """
  203. 提取 UNIT 的回复文本
  204. :param parsed: UNIT 解析结果
  205. :param intent: 意图的名称
  206. :returns: UNIT 的回复文本
  207. """
  208. if parsed and "result" in parsed and "response_list" in parsed["result"]:
  209. response_list = parsed["result"]["response_list"]
  210. if intent == "":
  211. try:
  212. return response_list[0]["action_list"][0]["say"]
  213. except Exception as e:
  214. logger.warning(e)
  215. return ""
  216. for response in response_list:
  217. if "schema" in response and "intent" in response["schema"] and response["schema"]["intent"] == intent:
  218. try:
  219. return response["action_list"][0]["say"]
  220. except Exception as e:
  221. logger.warning(e)
  222. return ""
  223. return ""
  224. else:
  225. return ""