作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
在有很多功能的情况下,与软件交互可能是一项艰巨的任务。 在某些情况下,执行类似的操作需要重复步骤,例如每次执行操作时导航菜单或填写表单。 聊天机器人是虚拟助手,可以帮助软件系统的用户访问信息或执行操作,而无需经历漫长的过程。 其中许多助手都是对话式的,这提供了一种更自然的方式与系统交互。
要创建对话式聊天机器人,您可以使用 Dialogflow 等平台来帮助您设计高水平的聊天机器人。 或者,您可以使用 spaCy 之类的库自己构建一个,这是一个快速且强大的基于 Python 的自然语言处理 (NLP) 库。 spaCy 提供了有用的功能,例如确定单词在语句中所属的词类,查找两个语句在含义上的相似程度等等。
在本教程中,您将创建一个聊天机器人,它不仅可以帮助用户简化与软件系统的交互,而且还足够智能,可以使用 自然语言 (本教程中的美式英语)与用户进行交流。 聊天机器人将使用 OpenWeather API 告诉用户世界上任何城市的当前天气情况,但您可以实现聊天机器人以使用另一个 API 处理用例。
先决条件
在开始之前,您将需要以下内容:
- 安装 Python 3 并设置编程环境。 您可以使用 如何安装 Python 3 和设置本地编程环境 教程之一为您的机器完成此操作。
- OpenWeather 的 API 密钥。 访问 OpenWeather 网站 创建一个帐户。 请务必确认您的电子邮件地址。 注册成功后,访问API密钥页面查看自动为您的账户创建的API密钥。 该键应该是一个字母数字字符序列。
本教程假设您已经熟悉 Python — 如果您想提高对 Python 的了解,请查看我们的 如何在 Python 3 中编码系列。 本教程不需要预知自然语言处理。
第 1 步 — 设置您的环境
在此步骤中,您将安装 spaCy
库,该库将帮助您的聊天机器人理解用户的句子。
按照 Prerequisites 设置 Python 后,您将拥有一个虚拟环境。 让我们激活那个环境。
确保您位于设置环境的目录中,然后运行以下命令:
source my_env/bin/activate
现在安装 spaCy:
pip install -U spacy
最后,您将下载一个语言模型。 spaCy 的 语言模型 是预训练的 NLP 模型,您可以使用它来处理语句以提取含义。 您将使用英语语言模型,因此您将下载它。
运行以下命令:
python -m spacy download en_core_web_md
如果您遇到如下错误:
OutputERROR: Failed building wheel for en-core-web-md
你需要安装wheel
:
pip install -U wheel
然后再次下载英文模型。
要确认您已正确安装 spaCy,请打开 Python 解释器:
python
接下来,导入 spaCy 并加载英文模型:
>>> import spacy >>> nlp = spacy.load("en_core_web_md")
如果这两个语句执行没有任何错误,那么你已经安装了 spaCy。
现在关闭 Python 解释器:
>>> exit()
您现在拥有开始使用聊天机器人所需的一切。 在下一部分中,您将创建一个脚本来查询 OpenWeather API 以获取城市的当前天气。
第 2 步 - 创建城市天气计划
在本节中,您将创建一个脚本,该脚本接受用户的城市名称,查询 OpenWeather API 以获取该城市的当前天气,并显示响应。
首先,使用您喜欢的编辑器创建并打开一个名为 weather_bot.py
的 Python 文件:
nano weather_bot.py
接下来,您将创建一个 函数 从 OpenWeather API 获取城市的当前天气。 该函数将城市名称作为参数,返回城市的天气描述。
将以下代码添加到您的 weather_bot.py
文件中:
天气机器人.py
import requests api_key = "your_api_key" def get_weather(city_name): api_url = "http://api.openweathermap.org/data/2.5/weather?q={}&appid={}".format(city_name, api_key) response = requests.get(api_url) response_dict = response.json() weather = response_dict["weather"][0]["description"] if response.status_code == 200: return weather else: print('[!] HTTP {0} calling [{1}]'.format(response.status_code, api_url)) return None
首先,导入 requests
库,以便能够使用并发出 HTTP 请求。 确保将 your_api_key
替换为您自己的 API 密钥。 下一行开始定义函数 get_weather()
以检索指定城市的天气。
在此函数中,您构建 OpenWeather API 的 URL。 该 URL 返回城市的天气信息(温度、天气描述、湿度等),并以 JSON 格式提供结果。 之后,您向 API 端点发出 GET 请求,将结果存储在 response
变量中,然后将响应转换为 Python dictionary 以便于访问。
在下一行,您仅将天气描述提取到 weather
变量中,然后确保 API 响应的状态代码为 200
(意味着请求没有问题)。 最后,您返回天气描述。
如果请求有问题,状态码会打印到控制台,然后返回 None
。
要测试脚本,请使用您选择的城市(例如,伦敦)调用 get_weather()
函数并打印结果。 在您的函数后面添加突出显示的代码:
~/weather_bot.py
import requests def get_weather(city_name): ... return weather weather = get_weather("London") print(weather)
保存并运行脚本:
python weather_bot.py
您将收到如下结果:
Outputscattered clouds
成功完成后,您现在可以从脚本中删除最后两行。
打开它:
nano weather_bot.py
然后删除文件末尾突出显示的两行:
~/weather_bot.py
import requests def get_weather(city_name): ... return weather weather = get_weather("London") print(weather)
保存并关闭文件。
您现在有一个函数可以返回特定城市的天气描述。
在下一步中,您将创建一个聊天机器人,能够确定用户是否想要获取城市的当前天气,如果是,聊天机器人将使用 get_weather()
函数做出适当的响应。
第三步——创建聊天机器人
在前两个步骤中,您安装了 spaCy 并创建了一个获取特定城市天气的函数。 现在,您将创建一个聊天机器人,使用 weather_bot.py
脚本以自然语言与用户交互。
您将编写一个 chatbot()
函数,将用户的语句与表示检查城市天气的语句进行比较。 为了进行这种比较,您将使用 spaCy similarity() 方法。 该方法计算两个语句的语义相似度,即它们在含义上的相似程度。 这将帮助您确定用户是否正在尝试查看天气。
首先,打开脚本:
nano weather_bot.py
然后,导入 spaCy 并加载英语语言模型:
~/weather_bot.py
import spacy import requests nlp = spacy.load("en_core_web_md") . . .
在文件中的 get_weather()
函数之后,创建一个表示聊天机器人的 chatbot()
函数,它将接受用户的语句并返回响应。
按照您的定义,添加突出显示的代码以为您将要比较的两个语句创建 tokens。 标记是语句中不同的有意义的部分,例如单词和标点符号。 这是允许 spaCy 计算语义相似度所必需的:
~/weather_bot.py
import spacy . . . def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement)
这里 weather
和 statement
变量包含 spaCy 标记,这是将每个相应的字符串传递给 nlp()
函数的结果。
保存并关闭您的文件。
接下来,您将向 chatbot()
函数引入 spaCy similarity()
方法。 similarity()
方法将两个语句的语义相似度计算为 0
和 1
之间的值,其中数字越大表示相似度越高。 您需要指定相似度必须具有的最小值,以便确定用户想要检查天气。
例如,如果您检查语句 2 和 3 与以下语句 1 的相似性,您会得到:
- 一个城市的当前天气
- 伦敦的天气如何? (相似度 = 0.86)
- 花生酱和果冻(相似度 = 0.31)
要亲自尝试,请打开 Python 解释器:
python
接下来,导入 spaCy 并加载英文模型:
>>> import spacy >>> nlp = spacy.load("en_core_web_md")
现在让我们从语句 1 和 2 创建标记:
>>> statement1 = nlp("Current weather in a city") >>> statement2 = nlp("What is the weather in London?")
最后,让我们得到两个语句的语义相似度:
>>> print(statement1.similarity(statement2))
您将收到如下结果:
Output0.8557684354027663
设置较低的最小值(例如,0.1)将导致聊天机器人通过将语句(如语句 3)与语句 1 相似来误解用户,这是不正确的。 设置一个过高的最小值(如 0.9)将排除一些实际上与语句 1 相似的语句,如语句 2。
为了本教程,我们将任意选择 0.75,但您可能希望在处理项目时测试不同的值。
让我们将此值添加到脚本中。 首先,打开文件:
nano weather_bot.py
然后添加以下突出显示的代码以引入最小值:
~/weather_bot.py
import spacy . . . def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement) min_similarity = 0.75
现在检查用户陈述与天气陈述的相似度是否大于或等于您指定的最小相似度值。 添加以下突出显示的 if
语句来检查这一点:
~/weather_bot.py
import spacy . . . def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement) min_similarity = 0.75 if weather.similarity(statement) >= min_similarity: pass
最后一步是从用户语句中提取城市,以便您可以将其传递给 get_weather()
函数以从 API 调用中检索天气。 添加以下突出显示的 for 循环 来实现这一点:
~/weather_bot.py
import spacy ... def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement) min_similarity = 0.75 if weather.similarity(statement) >= min_similarity: for ent in statement.ents: if ent.label_ == "GPE": # GeoPolitical Entity city = ent.text break
为此,您正在使用 spaCy 的 命名实体识别 功能。 一个 命名实体 是一个真实世界的名词,它有一个名字,就像一个人,或者在我们的例子中,一个城市。 您想从用户的语句中提取城市名称。
要提取城市名称,您需要获取用户语句中的所有命名实体,并检查其中哪些是地缘政治实体(国家、州、城市)。 为此,您循环遍历 spaCy 从 ents
属性中的语句中提取的所有实体,然后检查实体标签(或类)是否是代表地缘政治实体的“GPE”。 如果是,则将实体的名称(其文本)保存在名为 city
的变量中。
您还需要通过添加 else
块来捕获未输入城市的情况:
~/weather_bot.py
import spacy ... def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement) min_similarity = 0.75 if weather.similarity(statement) >= min_similarity: for ent in statement.ents: if ent.label_ == "GPE": # GeoPolitical Entity city = ent.text break else: return "You need to tell me a city to check."
现在你有了城市,你可以调用 get_weather()
函数:
~/weather_bot.py
import spacy ... def chatbot(statement): weather = nlp("Current weather in a city") statement = nlp(statement) min_similarity = 0.75 if weather.similarity(statement) >= min_similarity: for ent in statement.ents: if ent.label_ == "GPE": # GeoPolitical Entity city = ent.text break else: return "You need to tell me a city to check." city_weather = get_weather(city) if city_weather is not None: return "In " + city + ", the current weather is: " + city_weather else: return "Something went wrong." else: return "Sorry I don't understand that. Please rephrase your statement."
回想一下,如果 OpenWeather API 返回错误,则将错误代码打印到终端,然后 get_weather()
函数返回 None
。 在此代码中,您首先检查 get_weather()
函数是否返回 None
。 如果不是,则返回该城市的天气,但如果是,则返回一个字符串,说明出现问题。 最后的else
块是处理用户语句的相似度值没有达到阈值的情况。 在这种情况下,您要求用户重新表述他们的陈述。
完成所有这些之后,您现在拥有一个聊天机器人,能够以对话的方式告诉用户城市的天气情况。 该机器人与基于规则的聊天机器人之间的区别在于,用户不必每次都输入相同的语句。 相反,他们可以用不同的方式表达他们的请求,甚至打错字,但由于 spaCy 的 NLP 功能,聊天机器人仍然能够理解它们。
让我们测试一下机器人。 调用 chatbot()
函数并传入一个询问城市天气情况的语句,例如:
~/weather_bot.py
import spacy . . . def chatbot(statement): . . . response = chatbot("Is it going to rain in Rome today?") print(response)
保存并关闭文件,然后在终端中运行脚本:
python3 weather_bot.py
您将收到类似于以下内容的输出:
OutputIn Rome, the current weather is: clear sky
您已经成功创建了一个能够响应动态用户请求的智能聊天机器人。 您可以尝试更多示例来发现机器人的全部功能。 为此,您可以从 OpenWeather 和其他来源获取其他 API 端点。 扩展聊天机器人的另一种方法是使其能够响应更多用户请求。 为此,您可以将用户的陈述与多个选项进行比较,并找出语义相似度最高的选项。
结论
您已经创建了一个足够智能的聊天机器人来响应用户的陈述——即使用户以不同的方式表达他们的陈述。 聊天机器人使用 OpenWeather API 获取用户指定城市的当前天气。
要进一步改进聊天机器人,您可以:
- 查看 OpenWeather API 指南 了解您可以添加的其他天气功能。
- 访问 spaCy 网站 查看您可以实现的其他功能,以使聊天机器人更加智能。
- 通过我们关于 How To Work with Language Data in Python 3 using the Natural Language Toolkit (NLTK) 的教程提高您对自然语言处理的了解,或尝试 How To Perform Sentiment Analysis in Python 3 中的情感分析使用自然语言工具包 (NLTK)。
您可以在 DigitalOcean 存储库 中找到本教程的最终代码。