野仙生活网

野仙生活网

Rasa 基于知识库的问答 音乐百科机器人

民生 0

文章目录

    • 1. 使用 ActionQueryKnowledgeBase
      • 创建知识库
      • NLU数据
    • 2. 音乐机器人
      • nlu.yml
      • stories.yml
      • rules.yml
      • domain.yml
      • config.yml
      • endpoints.yml
      • data.json
      • 自定义动作 actions.py
      • 测试
      • 使用Neo4j

learn from https://github.com/Chinese-NLP-book/rasa_chinese_book_code

机器人返回了一个列表,用户说第X个,你得知道他说的是啥

1. 使用 ActionQueryKnowledgeBase

创建知识库

最简单的知识库 json 文件

{"song": [{"id": 0,"name": "晴天","singer": "周杰伦","album": "叶惠美","style": "流行,英伦摇滚"},{"id": 1,"name": "江南","singer": "林俊杰","album": "第二天堂","style": "流行,中国风"},],"singer": [{"id": 0,"name": "周杰伦","gender": "male","birthday": "1979/01/18"},{"id": 1,"name": "林俊杰","gender": "male","birthday": "1979/03/27"},]
}

格式 key : [object1,object2...]

InMemoryKnowledgeBase 实现中,每个 obj 都有至少有 name,id 属性

NLU数据

意图想要进行知识库信息查询

version: "3.0"
nlu:- intent: query_knowledge_baseexamples: |- 有什么好听的[歌曲](object_type)?- 有什么唱歌好听的[歌手](object_type)?- 给我列一些[男](gender)[歌手](object_type)- 给我列出一些[周杰伦](singer)的[歌曲](object_type)- [刚才那首](mention)属于什么[专辑](attribute)- [刚才那首](mention)是[谁](attribute)唱的- [刚才那首](mention)的[歌手](attribute)是谁- [那首歌](mention)属于什么[风格](attribute)?- [晴天](song)这首歌属于什么[专辑](attribute)?- [晴天](song)的[专辑](attribute)?- [江南](song)属于什么[专辑](attribute)?- [江南](song)在什么[专辑](attribute)里面?- [第一个](mention)人的[生日](attribute)- [周杰伦](singer)的[生日](attribute)
  • object_type歌曲 映射为 song
  • mention第一个,最后一个 的表述标注化为 1,LAST
  • attribute' 知识库中 obj 的属性,在 nlu 训练数据中都要标注为 attribute

同时 domain.yml 文件需要加入

entities:- object_type- mention- attribute- object-type- song- singer- gender
slots:attribute:type: anymappings:- type: from_entityentity: attributegender:type: anymappings:- type: from_entityentity: genderknowledge_base_last_object:type: anymappings:- type: customknowledge_base_last_object_type:type: anymappings:- type: customknowledge_base_listed_objects:type: anymappings:- type: customknowledge_base_objects:type: anymappings:- type: custommention:type: anymappings:- type: from_entityentity: mentionobject_type:type: anymappings:- type: from_entityentity: object_typesinger:type: anymappings:- type: from_entityentity: singersong:type: anymappings:- type: from_entityentity: song

2. 音乐机器人

tree

.
├── actions.py
├── config.yml
├── credentials.yml
├── data
│   ├── nlu.yml
│   ├── rules.yml
│   └── stories.yml
├── data.json
├── data_to_neo4j.py
├── dicts
│   ├── ordinal.txt
│   └── songs.txt
├── domain.yml
├── endpoints.yml
├── en_to_zh.json
├── index.html
├── index.js
├── __init__.py
├── Makefile
├── media
│   ├── demo2.png
│   └── demo.png
├── neo4j_knowledge_base.py
├── README.md
├── run_neo4j_in_docker.bash
└── tests└── basic.md

nlu.yml

version: "3.0"
nlu:- intent: goodbyeexamples: |- 拜拜- 再见- 拜- 退出- 结束- intent: greetexamples: |- 你好- 您好- Hello- hello- Hi- hi- 喂- 在么- intent: query_knowledge_baseexamples: |- 有什么好听的[歌曲](object_type)?- 有什么唱歌好听的[歌手](object_type)?- 给我列一些[歌曲](object_type)- 给我列一些[歌手](object_type)- 给我列一些[男](gender)[歌手](object_type)- 给我列一些[男](gender)的[歌手](object_type)- 给我列一些[女](gender)[歌手](object_type)- 给我列一些[女](gender)的[歌手](object_type)- 给我列一些[男性](gender)[歌手](object_type)- 给我列一些[女性](gender)[歌手](object_type)- 给我[男性](gender)[歌手](object_type)- 给我[女性](gender)[歌手](object_type)- 给我列出一些[周杰伦](singer)的[歌曲](object_type)- 给我列出[周杰伦](singer)的[歌曲](object_type)- 给我列出[周杰伦](singer)唱的[歌曲](object_type)- 列出[周杰伦](singer)的[歌曲](object_type)- 给我列[周杰伦](singer)的[歌曲](object_type)- [林俊杰](singer)都有什么[歌曲](object_type)- [林俊杰](singer)有什么[歌曲](object_type)- [刚才那首](mention)属于什么[专辑](attribute)- [刚才那首](mention)是[谁](attribute)唱的- [刚才那首](mention)的[歌手](attribute)是谁- [那首歌](mention)属于什么[风格](attribute)?- [最后一个](mention)属于什么[风格](attribute)?- [第一个](mention)属于什么[专辑](attribute)?- [第一个](mention)的[专辑](attribute)- [第一个](mention)是[谁](attribute)唱的?- [最后一个](mention)是[哪个](attribute)唱的?- [舞娘](song)是[哪个歌手](attribute)唱的?- [晴天](song)这首歌属于什么[专辑](attribute)?- [晴天](song)的[专辑](attribute)?- [江南](song)属于什么[专辑](attribute)?- [江南](song)在什么[专辑](attribute)里面?- [第一个](mention)人的[生日](attribute)- [周杰伦](singer)的[生日](attribute)- intent: play_songexamples: |- 播放这首歌- 播这首歌- intent: play_albumexamples: |- 播放这个专辑- 播这个专辑- synonym: "1"   # 同义词,第一个 -> 1examples: |- 第一个- 首个- 第一首- synonym: "2"examples: |- 第二个- 第二首- synonym: "3"examples: |- 第三个- 第三首- synonym: LASTexamples: |- 最后一个- 最后那个- 最后的- synonym: birthdayexamples: |- 生日- synonym: songexamples: |- 歌曲- synonym: singerexamples: |- 歌手- 谁- 哪个- 哪个歌手- synonym: albumexamples: |- 专辑- synonym: "4"examples: |- 第四个- 第四首- synonym: styleexamples: |- 风格- 类型- 流派- synonym: maleexamples: |- 男- 男性- synonym: famaleexamples: |- 女- 女性

stories.yml

version: "3.0"
stories:- story: greetsteps:- intent: greet- action: utter_greet- story: knowledge querysteps:- intent: query_knowledge_base- action: action_response_query- intent: query_knowledge_base- action: action_response_query- story: say goodbyesteps:- intent: goodbye- action: utter_goodbye

rules.yml

version: "3.0"
rules:- rule: 处理NLU低置信度时的规则steps:- intent: nlu_fallback- action: action_default_fallback- rule: 处理知识图谱查询steps:- intent: query_knowledge_base- action: action_response_query

domain.yml

version: "3.0"
session_config:session_expiration_time: 60carry_over_slots_to_new_session: true
intents:- goodbye- greet- query_knowledge_base:use_entities: []- play_song- play_album
entities:- object_type- mention- attribute- object-type- song- singer- gender
slots:attribute:type: anymappings:- type: from_entityentity: attributegender:type: anymappings:- type: from_entityentity: genderknowledge_base_last_object:type: anymappings:- type: customknowledge_base_last_object_type:type: anymappings:- type: customknowledge_base_listed_objects:type: anymappings:- type: customknowledge_base_objects:type: anymappings:- type: custommention:type: anymappings:- type: from_entityentity: mentionobject_type:type: anymappings:- type: from_entityentity: object_typesinger:type: anymappings:- type: from_entityentity: singersong:type: anymappings:- type: from_entityentity: song
responses:utter_greet:- text: 你好,我是 Silly, 一个可以利用知识图谱帮你查询歌手、音乐和专辑的机器人。utter_goodbye:- text: 再见!utter_default:- text: 系统不明白您说的话utter_ask_rephrase:- text: 抱歉系统没能明白您的话,请您重新表述一次
actions:- action_response_query- utter_goodbye- utter_greet- utter_default- utter_ask_rephrase

config.yml

recipe: default.v1
language: zhpipeline:- name: JiebaTokenizer- name: LanguageModelFeaturizermodel_name: bertmodel_weights: bert-base-chinese- name: RegexFeaturizer- name: DIETClassifierepochs: 1000learning_rate: 0.001- name: FallbackClassifierthreshold: 0.4ambiguity_threshold: 0.1- name: EntitySynonymMapper     policies:- name: MemoizationPolicy- name: TEDPolicy - name: RulePolicycore_fallback_threshold: 0.3core_fallback_action_name: "action_default_fallback"

endpoints.yml

action_endpoint:url: "http://localhost:5055/webhook"

data.json

{"song": [{"id": 0,"name": "晴天","singer": "周杰伦","album": "叶惠美","style": "流行,英伦摇滚"},{"id": 1,"name": "江南","singer": "林俊杰","album": "第二天堂","style": "流行,中国风"},{"id": 2,"name": "舞娘","singer": "蔡依林","album": "舞娘","style": "流行"},{"id": 3,"name": "后来","singer": "刘若英","album": "我等你","style": "流行,抒情,经典"}],"singer": [{"id": 0,"name": "周杰伦","gender": "male","birthday": "1979/01/18"},{"id": 1,"name": "林俊杰","gender": "male","birthday": "1979/03/27"},{"id": 2,"name": "蔡依林","gender": "female","birthday": "1980/09/15"},{"id": 3,"name": "刘若英","gender": "female","birthday": "1969/06/01"}]
}

自定义动作 actions.py

import os
import jsonfrom typing import Any, Dict, List, Textfrom rasa_sdk import utils
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.knowledge_base.actions import ActionQueryKnowledgeBase
from rasa_sdk.knowledge_base.storage import InMemoryKnowledgeBaseUSE_NEO4J = bool(os.getenv("USE_NEO4J", False))if USE_NEO4J:from neo4j_knowledge_base import Neo4jKnowledgeBaseclass EnToZh:def __init__(self, data_file):with open(data_file) as fd:self.data = json.load(fd)def __call__(self, key):return self.data.get(key, key)class MyKnowledgeBaseAction(ActionQueryKnowledgeBase):def name(self) -> Text:return "action_response_query"def __init__(self):if USE_NEO4J:print("using Neo4jKnowledgeBase")knowledge_base = Neo4jKnowledgeBase("bolt://localhost:7687", "neo4j", "43215678")else:print("using InMemoryKnowledgeBase")knowledge_base = InMemoryKnowledgeBase("data.json")super().__init__(knowledge_base)self.en_to_zh = EnToZh("en_to_zh.json")async def utter_objects(self,dispatcher: CollectingDispatcher,object_type: Text,objects: List[Dict[Text, Any]],) -> None:"""Utters a response to the user that lists all found objects.Args:dispatcher: the dispatcherobject_type: the object typeobjects: the list of objects"""if objects:dispatcher.utter_message(text="找到下列{}:".format(self.en_to_zh(object_type)))repr_function = await self.knowledge_base.get_representation_function_of_object(object_type)for i, obj in enumerate(objects, 1):dispatcher.utter_message(text=f"{i}: {repr_function(obj)}")else:dispatcher.utter_message(text="我没找到任何{}.".format(self.en_to_zh(object_type)))def utter_attribute_value(self,dispatcher: CollectingDispatcher,object_name: Text,attribute_name: Text,attribute_value: Text,) -> None:"""Utters a response that informs the user about the attribute value of theattribute of interest.Args:dispatcher: the dispatcherobject_name: the name of the objectattribute_name: the name of the attributeattribute_value: the value of the attribute"""if attribute_value:dispatcher.utter_message(text="{}的{}是{}。".format(self.en_to_zh(object_name),self.en_to_zh(attribute_name),self.en_to_zh(attribute_value),))else:dispatcher.utter_message(text="没有找到{}的{}。".format(self.en_to_zh(object_name), self.en_to_zh(attribute_name)))

测试

rasa train
rasa run --cors "*"
rasa run actions
python -m http.server

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用Neo4j

图数据库
docker 安装 docker run --env=NEO4J_AUTH=none --publish=7474:7474 --publish=7687:7687 neo4j

pip install neo4j

导入数据

python data_to_neo4j.py

windows

set USE_NEO4J=1
rasa run actions