|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- # encoding:utf-8
- import json
- import os
- import uuid
- from uuid import getnode as get_mac
-
- import requests
-
- import plugins
- from bridge.context import ContextType
- from bridge.reply import Reply, ReplyType
- from common.log import logger
- from plugins import *
-
- """利用百度UNIT实现智能对话
- 如果命中意图,返回意图对应的回复,否则返回继续交付给下个插件处理
- """
-
-
- @plugins.register(
- name="BDunit",
- desire_priority=0,
- hidden=True,
- desc="Baidu unit bot system",
- version="0.1",
- author="jackson",
- )
- class BDunit(Plugin):
- def __init__(self):
- super().__init__()
- try:
- curdir = os.path.dirname(__file__)
- config_path = os.path.join(curdir, "config.json")
- conf = None
- if not os.path.exists(config_path):
- raise Exception("config.json not found")
- else:
- with open(config_path, "r") as f:
- conf = json.load(f)
- self.service_id = conf["service_id"]
- self.api_key = conf["api_key"]
- self.secret_key = conf["secret_key"]
- self.access_token = self.get_token()
- self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
- logger.info("[BDunit] inited")
- except Exception as e:
- logger.warn("[BDunit] init failed, ignore ")
- raise e
-
- def on_handle_context(self, e_context: EventContext):
- if e_context["context"].type != ContextType.TEXT:
- return
-
- content = e_context["context"].content
- logger.debug("[BDunit] on_handle_context. content: %s" % content)
- parsed = self.getUnit2(content)
- intent = self.getIntent(parsed)
- if intent: # 找到意图
- logger.debug("[BDunit] Baidu_AI Intent= %s", intent)
- reply = Reply()
- reply.type = ReplyType.TEXT
- reply.content = self.getSay(parsed)
- e_context["reply"] = reply
- e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
- else:
- e_context.action = EventAction.CONTINUE # 事件继续,交付给下个插件或默认逻辑
-
- def get_help_text(self, **kwargs):
- help_text = "本插件会处理询问实时日期时间,天气,数学运算等问题,这些技能由您的百度智能对话UNIT决定\n"
- return help_text
-
- def get_token(self):
- """获取访问百度UUNIT 的access_token
- #param api_key: UNIT apk_key
- #param secret_key: UNIT secret_key
- Returns:
- string: access_token
- """
- url = "https://aip.baidubce.com/oauth/2.0/token?client_id={}&client_secret={}&grant_type=client_credentials".format(
- self.api_key, self.secret_key
- )
- payload = ""
- headers = {"Content-Type": "application/json", "Accept": "application/json"}
-
- response = requests.request("POST", url, headers=headers, data=payload)
-
- # print(response.text)
- return response.json()["access_token"]
-
- def getUnit(self, query):
- """
- NLU 解析version 3.0
- :param query: 用户的指令字符串
- :returns: UNIT 解析结果。如果解析失败,返回 None
- """
-
- url = (
- "https://aip.baidubce.com/rpc/2.0/unit/service/v3/chat?access_token="
- + self.access_token
- )
- request = {
- "query": query,
- "user_id": str(get_mac())[:32],
- "terminal_id": "88888",
- }
- body = {
- "log_id": str(uuid.uuid1()),
- "version": "3.0",
- "service_id": self.service_id,
- "session_id": str(uuid.uuid1()),
- "request": request,
- }
- try:
- headers = {"Content-Type": "application/json"}
- response = requests.post(url, json=body, headers=headers)
- return json.loads(response.text)
- except Exception:
- return None
-
- def getUnit2(self, query):
- """
- NLU 解析 version 2.0
-
- :param query: 用户的指令字符串
- :returns: UNIT 解析结果。如果解析失败,返回 None
- """
- url = (
- "https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token="
- + self.access_token
- )
- request = {"query": query, "user_id": str(get_mac())[:32]}
- body = {
- "log_id": str(uuid.uuid1()),
- "version": "2.0",
- "service_id": self.service_id,
- "session_id": str(uuid.uuid1()),
- "request": request,
- }
- try:
- headers = {"Content-Type": "application/json"}
- response = requests.post(url, json=body, headers=headers)
- return json.loads(response.text)
- except Exception:
- return None
-
- def getIntent(self, parsed):
- """
- 提取意图
-
- :param parsed: UNIT 解析结果
- :returns: 意图数组
- """
- if parsed and "result" in parsed and "response_list" in parsed["result"]:
- try:
- return parsed["result"]["response_list"][0]["schema"]["intent"]
- except Exception as e:
- logger.warning(e)
- return ""
- else:
- return ""
-
- def hasIntent(self, parsed, intent):
- """
- 判断是否包含某个意图
-
- :param parsed: UNIT 解析结果
- :param intent: 意图的名称
- :returns: True: 包含; False: 不包含
- """
- if parsed and "result" in parsed and "response_list" in parsed["result"]:
- response_list = parsed["result"]["response_list"]
- for response in response_list:
- if (
- "schema" in response
- and "intent" in response["schema"]
- and response["schema"]["intent"] == intent
- ):
- return True
- return False
- else:
- return False
-
- def getSlots(self, parsed, intent=""):
- """
- 提取某个意图的所有词槽
-
- :param parsed: UNIT 解析结果
- :param intent: 意图的名称
- :returns: 词槽列表。你可以通过 name 属性筛选词槽,
- 再通过 normalized_word 属性取出相应的值
- """
- if parsed and "result" in parsed and "response_list" in parsed["result"]:
- response_list = parsed["result"]["response_list"]
- if intent == "":
- try:
- return parsed["result"]["response_list"][0]["schema"]["slots"]
- except Exception as e:
- logger.warning(e)
- return []
- for response in response_list:
- if (
- "schema" in response
- and "intent" in response["schema"]
- and "slots" in response["schema"]
- and response["schema"]["intent"] == intent
- ):
- return response["schema"]["slots"]
- return []
- else:
- return []
-
- def getSlotWords(self, parsed, intent, name):
- """
- 找出命中某个词槽的内容
-
- :param parsed: UNIT 解析结果
- :param intent: 意图的名称
- :param name: 词槽名
- :returns: 命中该词槽的值的列表。
- """
- slots = self.getSlots(parsed, intent)
- words = []
- for slot in slots:
- if slot["name"] == name:
- words.append(slot["normalized_word"])
- return words
-
- def getSayByConfidence(self, parsed):
- """
- 提取 UNIT 置信度最高的回复文本
-
- :param parsed: UNIT 解析结果
- :returns: UNIT 的回复文本
- """
- if parsed and "result" in parsed and "response_list" in parsed["result"]:
- response_list = parsed["result"]["response_list"]
- answer = {}
- for response in response_list:
- if (
- "schema" in response
- and "intent_confidence" in response["schema"]
- and (
- not answer
- or response["schema"]["intent_confidence"]
- > answer["schema"]["intent_confidence"]
- )
- ):
- answer = response
- return answer["action_list"][0]["say"]
- else:
- return ""
-
- def getSay(self, parsed, intent=""):
- """
- 提取 UNIT 的回复文本
-
- :param parsed: UNIT 解析结果
- :param intent: 意图的名称
- :returns: UNIT 的回复文本
- """
- if parsed and "result" in parsed and "response_list" in parsed["result"]:
- response_list = parsed["result"]["response_list"]
- if intent == "":
- try:
- return response_list[0]["action_list"][0]["say"]
- except Exception as e:
- logger.warning(e)
- return ""
- for response in response_list:
- if (
- "schema" in response
- and "intent" in response["schema"]
- and response["schema"]["intent"] == intent
- ):
- try:
- return response["action_list"][0]["say"]
- except Exception as e:
- logger.warning(e)
- return ""
- return ""
- else:
- return ""
|