由于人工智能浪潮的兴起,这些天来,用户已经期望应用既智能又知道使用背景的情况。 IBM Watson提供了各种与自然语言相关的服务,您可以使用这些服务来创建此类应用程序。
例如,您可以使用其自然语言理解服务从用户正在阅读的任何文本中提取关键字,实体,情感以及许多其他语义细节。 并且,如果文本恰好是外语,则可以使用“ 语言翻译器”服务来识别该语言并将其翻译为用户可以理解的一种语言。
在本教程中,我将向您介绍其中的一些服务,向您展示如何创建一个应用程序,该应用程序可以将德语网页翻译成英语并从中提取情感,重要实体和情感。
1.激活服务
今天,我们将使用三个Watson服务,并且每个服务都需要单独激活。 因此,打开您的IBM Bluemix 仪表板 ,然后按创建按钮。
我们将要激活的第一个服务是文档转换服务,该服务使我们能够将HTML,PDF和DOCX文档转换为纯文本或JSON。 从目录中选择它,给它取一个有意义的名称,然后按Create按钮。

接下来,返回目录并选择Language Translator服务。 它支持多种广泛使用的语言,并且默认情况下可以处理三个领域的文本:新闻,对话和专利。 尽管前两个域适用于大多数文本,但最后一个域对于包含大量技术或法律术语的文本可能更准确。
在其配置页面中,为服务指定一个有意义的名称,然后按“ 创建”按钮。

返回目录并选择“ 自然语言理解”服务。 我们将使用此服务从非结构化文本中提取情感,实体和情感。 同样,在配置屏幕中给它取一个有意义的名称,然后按“ 创建”按钮。

如果现在打开仪表板,您应该能够看到以下内容:

所有这三个服务都有与之关联的唯一登录凭据。 您必须记下所有这些内容,因为以后需要它们。 要确定任何服务的凭据,请在仪表板上将其选中,打开其“ 服务凭据”选项卡,然后按“ 查看凭据”按钮。
2.项目设置
为了能够在Android Studio项目中使用这三种服务,我们必须在app
模块的build.gradle文件中添加Watson Java SDK作为implementation
依赖项 。
implementation 'com.ibm.watson.developer_cloud:java-sdk:3.9.1'
此外,我们将把Fuel库用作HTTP客户端,因此也将其添加为implementation
依赖项。
implementation 'com.github.kittinunf.fuel:fuel-android:1.10.0'
仅当我们的应用程序具有INTERNET
权限时,Fuel和Watson Java SDK才可以工作,因此请在清单文件中提出要求。
<uses-permission android:name="android.permission.INTERNET"/>
接下来,将包含所有三个服务的用户名和密码的<string>
标记添加到strings.xml文件。
<string name="document_conversion_username">USERNAME1</string>
<string name="document_conversion_password">PASSWORD1</string>
<string name="language_translator_username">USERNAME2</string>
<string name="language_translator_password">PASSWORD2</string>
<string name="natural_language_understanding_username">USERNAME3</string>
<string name="natural_language_understanding_password">PASSWORD3</string>
最后,为了使代码简洁,在本教程中,我们将使用Kotlin而不是Java,因此请确保已启用Kotlin支持。
3.使用文档转换服务
我们将使用Watson Document Conversion服务将HTML网页转换为纯文本。 要允许用户输入网页地址,请将EditText
小部件添加到活动的布局中。 此外,包括一个TextView
小部件,以纯文本形式显示网页的内容。 为了确保较长的网页内容不会被截断,建议您将其放在ScrollView
小部件中。
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/documentURL"
android:inputType="textUri"
android:hint="URL"
android:imeOptions="actionGo"
/>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_below="@+id/documentURL">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/documentContents"
/>
</ScrollView>
在上面的代码中,您可以看到EditText
小部件的imeOptions
属性设置为actionGo
。 当用户完成地址输入后,它可以使用户按下虚拟键盘上的“开始”按钮。 要收听该按钮按下事件,请将以下Kotlin代码添加到活动的onCreate()
方法中:
documentURL.setOnEditorActionListener { _, action, _ ->
if (action == EditorInfo.IME_ACTION_GO) {
// More code here
}
false
}
在事件侦听器内部,我们需要做的第一件事就是确定用户键入的URL。 通过访问EditText
小部件的text
属性,我们可以轻松地做到这一点。 获得URL后,可以使用Fuel的httpGet()
方法下载网页的内容。
因为我们希望httpGet()
方法异步运行,所以必须使用responseString()
方法向其添加回调,这也允许我们将下载的内容作为字符串处理。
val url:String = documentURL.text.toString()
url.httpGet().responseString { _, _, result ->
val (document, _) = result
if (err == null) {
// More code here
}
}
现在是时候创建DocumentConversion
类的实例了,该实例具有我们与Document Conversion服务交互所需的所有方法。 它的构造函数期望版本日期以及服务的登录凭据。
val documentConverter = DocumentConversion(
DocumentConversion.VERSION_DATE_2015_12_01,
resources.getString(R.string.document_conversion_username),
resources.getString(R.string.document_conversion_password)
)
Watson Java SDK不允许我们直接将字符串传递给文档转换服务。 它需要File
对象。 因此,现在让我们使用File
类的createTempFile()
方法创建一个临时文件,并使用writeText()
方法写入下载到它的网页的内容。
val tempFile = File.createTempFile("temp_file", null)
tempFile.writeText(document, Charsets.UTF_8)
此时,我们可以调用convertDocumentToText()
方法并将临时文件传递给它以开始转换。 该方法还需要临时文件的MIME类型,因此请不要忘记将其包括在内。 转换完成后,只需将纯文本分配给TextView
小部件的text
属性即可显示纯文本。
以下代码显示了如何在新线程内执行转换并更新UI线程中的TextView
:
AsyncTask.execute {
val plainText = documentConverter
.convertDocumentToText(tempFile, "text/html")
.execute()
runOnUiThread {
documentContents.text = plainText
}
}
您可以立即运行该应用程序,然后键入德语网页的URL,以查看文档转换服务的运行情况。

4.使用语言翻译服务
通过语言翻译服务,我们现在将德语的纯文本转换为英语。
为了让用户手动开始翻译,而无需更新布局,而是让菜单添加到活动中。 为此,首先创建一个新的菜单资源文件并向其中添加以下代码:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_translate"
android:title="Translate"
app:showAsAction = "never" />
<item android:id="@+id/action_analyze"
android:title="Analyze"
app:showAsAction = "never" />
</menu>
如您所见,以上代码创建了一个包含两个选项的菜单:翻译和分析。 在此步骤中,我们将仅使用第一个选项。
要渲染菜单,我们必须在活动的onCreateOptionsMenu()
方法内将其充气。
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return super.onCreateOptionsMenu(menu)
}
通过重写onOptionsItemSelected()
方法,我们可以知道用户何时使用菜单。 此外,我们可以通过检查itemId
来确定用户按下了哪个项目。 以下代码检查用户是否选择了笔译选项。
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
if(item?.itemId == R.id.action_translate) {
// More code here
}
return true
}
就像文档服务一样,语言翻译器服务也有专用的类,使我们可以与之交互。 您可能已经猜到了,它叫做LanguageTranslator
。 要创建该类的实例,我们只需要将服务的登录凭据传递给其构造函数。
val translator = LanguageTranslator(
resources.getString(R.string.language_translator_username),
resources.getString(R.string.language_translator_password)
)
该类具有一个translate()
方法,我们现在可以使用该方法将德语文本翻译为英语。 作为参数,它希望文本翻译为字符串,文本的当前语言和所需的语言。
翻译成功完成后,我们将可以访问TranslationResult
对象,该对象的firstTranslation
属性包含已翻译的文本。
以下代码显示了如何执行转换并在TextView
小部件中呈现结果。
AsyncTask.execute {
val translatedDocument = translator
.translate(
documentContents.text
.toString(),
Language.GERMAN,
Language.ENGLISH
).execute()
runOnUiThread {
documentContents.text = translatedDocument
.firstTranslation
}
}
现在,您可以再次运行该应用程序,输入德语网页的URL,然后使用菜单将其内容翻译为英语。

5.使用自然语言理解服务
最后,要对翻译后的文本进行语义分析并从中提取出许多重要的细节,我们可以使用NaturalLanguageUnderstanding
类,该类充当Natural Language谅解服务的客户端。
以下代码显示了仅当用户按下在上一步中创建的菜单的第二个选项时,如何初始化客户端:
if(item?.itemId == R.id.action_analyze) {
val analyzer = NaturalLanguageUnderstanding(
NaturalLanguageUnderstanding.VERSION_DATE_2017_02_27,
resources.getString(
R.string.natural_language_understanding_username),
resources.getString(
R.string.natural_language_understanding_password)
)
// More code here
}
与其他与自然语言相关的服务相比,使用自然语言理解服务要稍微复杂一些,主要是因为它具有大量功能。
现在,假设我们要确定翻译文本的整体情感,并提取其提及的所有主要实体。 每个实体本身都可以具有与之关联的情感和情感,所以可以说我们也要提取这些情感和情感。
为了告诉服务我们要提取所有实体以及与之关联的情感和情感,我们需要一个EntitiesOptions
对象,可以使用EntitiesOptions.Builder
类创建该对象。
val entityOptions = EntitiesOptions.Builder()
.emotion(true)
.sentiment(true)
.build()
同样,要告诉服务我们需要文本的整体感觉,我们需要一个SentimentOptions
对象。
val sentimentOptions = SentimentOptions.Builder()
.document(true)
.build()
现在必须将SentimentOptions
和EntitiesOptions
对象捆绑在一起以形成Features
对象,该Features
对象可用于组成AnalyzeOptions
对象。 AnalyzeOptions
对象是上述所有对象中最重要的,因为它是您指定要分析的文本的位置。
val features = Features.Builder()
.entities(entityOptions)
.sentiment(sentimentOptions)
.build()
val analyzerOptions = AnalyzeOptions.Builder()
.text(documentContents.text.toString())
.features(features)
.build()
一旦AnalyzeOptions
对象准备就绪,我们就可以将其传递给AnalyzeOptions
analyze()
方法来开始分析。
AsyncTask.execute {
val results = analyzer.analyze(analyzerOptions).execute()
// More code here
}
分析的结果是一个AnalysisResults
对象,其中包含我们要求的所有信息。
要确定文本的总体情感,我们必须首先使用sentiment.document.score
属性提取总体情感分数。 情感分数不过是浮点数。 如果为零,则表示情绪中立。 如果是消极或积极,则情绪也是消极或积极的。
val overallSentimentScore = results.sentiment.document.score
var overallSentiment = "Positive"
if(overallSentimentScore < 0.0)
overallSentiment = "Negative"
if(overallSentimentScore == 0.0)
overallSentiment = "Neutral"
var output = "Overall sentiment: ${overallSentiment}\n\n"
接下来,通过遍历AnalysisResults
对象中存在的entities
列表,我们可以分别处理每个实体。 默认情况下,每个实体都有与之关联的类型。 例如,服务可以判断实体是人,公司还是车辆。 目前,它可以识别450多种不同类型的实体。
因为我们要求他们,所以每个实体现在也将具有情感得分和与之相关的情感。
我们可以通过简单地使用sentiment.score
属性来确定情感分数。 但是,确定与实体相关的情感并不是那么简单。 沃森目前支持五种情绪:愤怒,喜悦,厌恶,恐惧和悲伤。 每个实体将具有全部五个情感,但是与每个情感相关联的值不同,从而指定服务对该情感正确的信心。 因此,要确定正确的情感,我们必须选择具有最高价值的情感。
以下代码列出了每个实体及其类型,情感分数和情感:
for(entity in results.entities) {
output += "${entity.text} (${entity.type})\n"
val validEmotions = arrayOf("Anger", "Joy", "Disgust",
"Fear", "Sadness")
val emotionValues = arrayOf(
entity.emotion.anger,
entity.emotion.joy,
entity.emotion.disgust,
entity.emotion.fear,
entity.emotion.sadness
)
val currentEmotion = validEmotions[
emotionValues.indexOf(
emotionValues.max()
)
]
output += "Emotion: ${currentEmotion}, " +
"Sentiment: ${entity.sentiment.score}" +
"\n\n"
}
为了显示我们生成的输出,我们可以再次更新TextView
小部件。
runOnUiThread {
documentContents.text = output
}
此时,您可以再次运行该应用程序以查看所有三个服务一起工作。

结论
您现在知道如何使用Watson提供的三种与自然语言相关的最广泛使用的服务。 在本教程中,您还看到了使用Watson Java SDK使所有服务协同工作以创建智能Android应用程序有多么容易。