导言
使用Oscova(一个bot开发框架)创建一个SQL数据库的自然语言界面。
Oscova和Siml的区别在于,与Siml不同的是,Oscova不依赖于严格的模式。相反,它依赖于用户输入和保存的表达式之间的语义和语法。Oscova使开发人员能够创建利用对话、指令、文本和名词识别等概念和功能的机器人,以及不需要连接到任何在线API的额外优势。
话虽如此,如果您仍然倾向于编写严格的用户输入模式,那么Siml可能是你更好的选择
在本文中,我们将利用Oscova创建一个我们与机器人对话的employees数据库。
前提条件
C#编程知识 使用SQL进行数据库管理。 WPF应用程序和XAML的基本思想。架构
Oscova的核心部分主要包括以下几个方面:
对话框:用以发送指令、对话、文本的输入框 意图:机器人在以下情况下执行/调用的操作:发送指令。 表达式:类似于用户输入的模板模式或示例。实现步骤
首先,我们将使用所有必需的GUI元素创建一个WPF应用程序项目。 将基本库导入到我们的项目中。 创建一个用于与数据库交互的数据库实用类。 将GUI与机器人事件连接。 为几个数据库列创建实体识别器。 创建对话框和意图 测试我们的机器人。如果发现任何概念难以掌握,只需打开项目,并参考代码。一旦浏览了项目的代码库,事情就会变得容易得多。
搭建WPF界面
让我们首先创建一个WPF项目,它将拥有我们与聊天机器人交互所需的所有GUI内容。
在整篇文章中,我将假设您正在使用VisualStudio。如果您是在Linux环境中,那么使用GTK的Mono应该就足够了,但我将在本文中继续使用VS。
启动VisualStudio 点击File,选择New然后选择Project.. 在下面Templates,选择Windows然后选择WPF应用 命名项目NLI-Database-Oscova(如果您计划复制下面的代码,则非常重要)。NLI是缩写词自然语言接口.WPF应用程序需要几个组件。
文本框:用于用户输入。 按钮:发送用户输入。 选项卡控件:第一个选项卡用于查看DataGrid(用于数据库),第二个选项卡用于查看JSON结果。在解决方案资源管理器中双击MainWindow.xaml并将XAML替换为下面的代码。
<c1></c1><Window x:Class=”NLI_Database_Oscova.MainWindow” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Title=”Natural Language Interface using Oscova” Height=”450″ Width=”560″ WindowStartupLocation=”CenterScreen”> <Grid> <TabControl> <TabItem Header=”Interaction”> <Grid> <Grid.RowDefinitions> <RowDefinition Height=”35″/> <RowDefinition Height=”50*”/> <RowDefinition Height=”232*”/> </Grid.RowDefinitions> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=”414*”/> <ColumnDefinition Width=”100″/> </Grid.ColumnDefinitions> <TextBox Name=”InputBox” TextAlignment=”Center” CharacterCasing=”Upper” KeyDown=”InputBox_OnKeyDown”/> <Button Name=”ExecuteButton” Content=”Evaluate” Grid.Column=”1″ Click=”EvaluateButton_OnClick”/> </Grid> <Label Grid.Row=”1″ Name=”ResponseLabel” Content=”No Response Yet” VerticalContentAlignment=”Top” /> <TabControl Grid.Row=”2″> <TabItem Header=”Table”> <DataGrid Name=”EmployeeGrid” FontSize=”14″ /> </TabItem> <TabItem Header=”JSON Result”> <TextBox Name=”ResultBox” IsReadOnly=”True” AcceptsReturn=”True” VerticalScrollBarVisibility=”Auto” /> </TabItem> </TabControl> </Grid> </TabItem> <TabItem Header=”Examples”> <TextBox Name=”ExamplesBox” VerticalScrollBarVisibility=”Auto” HorizontalScrollBarVisibility=”Auto” IsReadOnly=”True”/> </TabItem> </TabControl> </Grid> </Window>上面的代码添加了一个TabControl,其中有一个用于用户输入的文本框和一个Evluate(评估)按钮。
WPF应用程序应该如下所示:
导入Oscova和SQLite
现在,需要将Oscova导入到WPF应用程序中,Oscova是Syn.Bot框架的一部分,我们需要使用NuGet来引用包。
点击Tools,选择NuGet Package Manager并选择Package Manager Console 选择Install-Package Syn.Bot Bot框架将与一些外部依赖项一起引用。引用SQLite(用于数据库)
选择Install-Package System.Data.SQLite现在您已经成功地引用了所需的库。我们会继续用一些C#代码来开发。
数据库实用类
为了让对话变得简单,我们首先创建一个数据库实用程序类。右键单击Solution Explorer并选择Class。给类命名DatabaseUtility
替换DatabaseUtility用以下方法初始化。
using System.Data.SQLite; using System.IO; namespace NLI_Database_Oscova { public class DatabaseUtility { const string DataSource = “EmployeesTable.db”; public SQLiteCommand Command { get; set; } public SQLiteConnection Connection { get; set; } public MainWindow Window { get; } public DatabaseUtility(MainWindow window) { Window = window; } public void Initialize() { if (File.Exists(DataSource)) File.Delete(DataSource); Connection = new SQLiteConnection { ConnectionString = “Data Source=” + DataSource }; Connection.Open(); ExecuteCommand(“CREATE TABLE IF NOT EXISTS EMPLOYEES (ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Name VARCHAR(100) NOT NULL, Role VARCHAR(10), Age INTEGER NOT NULL, Salary INTEGER NOT NULL);”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(1, Lincoln, Manager, 43, 54000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(2, George, CEO, 46, 75000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(3, Rick, Admin, 32, 18000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(4, Jorge, Engineer, 28, 35000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(5, Ivan, Tech, 23, 34000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(6, Mark, Tech, 25, 34000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(7, Vincent, Support, 21, 20000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(8, Wang, Support, 20, 20000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(9, Ahmed, Tech, 24, 34000)”); ExecuteCommand(“INSERT INTO EMPLOYEES VALUES(10, Krishna, Admin, 25, 18000)”); } private void ExecuteCommand(string commandText) { Command = new SQLiteCommand(Connection) { CommandText = commandText }; Command.ExecuteNonQuery(); } } }等等,还有更多要补充的。内部DatabaseUtility类添加以下方法。
public void Evaluate(string commandText) { Window.UpdateDataGrid(commandText); } public void UpdatePropertyByName(string employeeName, string propertyName, string propertyValue) { var updateString = $”UPDATE EMPLOYEES SET {propertyName}={propertyValue} WHERE UPPER(Name) LIKE UPPER(%{employeeName}%);”; var selectString = $”SELECT * FROM EMPLOYEES WHERE UPPER(Name) LIKE UPPER({employeeName}%);”; Evaluate(updateString); Evaluate(selectString); } public void UpdatePropertyById(string employeeId, string propertyName, string propertyValue) { var updateString = $”UPDATE EMPLOYEES SET {propertyName}={propertyValue} WHERE ID={employeeId};”; var selectString = $”SELECT * FROM EMPLOYEES WHERE ID={employeeId};”; Evaluate(updateString); Evaluate(selectString); } public void PropertyByName(string employeeName, string propertyName) { var selectString = $”SELECT {propertyName} FROM Employees WHERE UPPER(Name) LIKE UPPER(%{employeeName}%);”; Evaluate(selectString); } public void PropertyByRole(string employeeRole, string propertyName) { var selectString = $”SELECT DISTINCT {propertyName} FROM Employees WHERE UPPER(Role) LIKE UPPER(%{employeeRole}%)”; Evaluate(selectString); } public void EmployeeByName(string employeeName) { var selectString = $”SELECT * FROM Employees WHERE UPPER(Name) LIKE UPPER(%{employeeName}%);”; Evaluate(selectString); } public void EmployeeByRole(string employeeRole) { var selectString = $”SELECT * FROM Employees WHERE UPPER(Role) LIKE UPPER(%{employeeRole}%);”; Evaluate(selectString); } public void Close() { Command.Dispose(); Connection.Dispose(); }这个类MainWindow作为其结构参数之一。我们在以后的项目中会用到它。
这个Initialize方法帮助我们为我们的employees数据库。然后有一些帮助函数,如UpdatePropertyByName, UpdatePropertyById诸若此类。当调用某些意图时,我们的聊天机器人将使用这些函数。
您现在不必担心代码。这一切在后面的文章中都是有意义的。
主窗口
在Solution Explorer右击MainWindow.cs并选择View Code.
添加以下命名空间:
using System; using System.Data; using System.Data.SQLite; using System.Windows; using System.Windows.Input; using Syn.Bot.Oscova; using Syn.Bot.Oscova.Collection; using Syn.Bot.Oscova.Entities;将下列属性添加到MainwWindow班级。
public OscovaBot Bot { get; } public DatabaseUtility DatabaseUtility { get; }在构造函数中添加以下内容。
public MainWindow() { InitializeComponent(); Bot = new OscovaBot(); Bot.MainUser.ResponseReceived += (sender, args) => { ResponseLabel.Content = args.Response.Text; }; DatabaseUtility = new DatabaseUtility(this); DatabaseUtility.Initialize(); UpdateDataGrid(“SELECT * From Employees”); Bot.MainUser.Context.SharedData.Add(DatabaseUtility); Bot.CreateRecognizer(“set”, new[] { “change”, “update”, “set” }); Bot.CreateRecognizer(“property”, new[] { “id”, “name”, “job”, “age”, “salary” }); //Parsers go here //Dialogs go here //Finally Train the Bot. Bot.Train(); }首先,我们使用实例化OscovaBot对象,分配聊天机器人属性。接下来我们处理ResponseReceived的事件MainUser若要显示响应的文本,使用ResponseLabel.
然后,我们创建一个新的实例DatabaseUtility类并调用Initialize()方法。可以忽略UpdateDataGrid()目前的方法。
因为我们需要DatabaseUtility在整个聊天过程中,我们接下来将它添加到MainUsers 里面
接下来,我们利用重载CreateRecognizer方法创建特定单词的识别器,如change, update诸若此类。
最后,我们添加Train()方法。
注:Oscova需要Train()方法在添加、创建或修改组件后调用一次。
有了这个,我们继续修复UpdateDataGrid()功能。将下列代码添加到MainWindow类。
public void UpdateDataGrid(string sql) { var dataSet = new DataSet(); var dataAdapter = new SQLiteDataAdapter(sql, DatabaseUtility.Connection); dataAdapter.Fill(dataSet); if (dataSet.Tables.Count > 0) { EmployeeGrid.ItemsSource = dataSet.Tables[0].DefaultView; } }上面的方法使我们能够在每次SQL调用之后更新DataGrid。你可能已经注意到了DatabaseUtility利用这种方法。
创建自定义实体识别器
到目前一切尚好。是时候创建一些实体识别器了。实体识别器只是IEntityRecognizer接口,该接口读取normalized用户输入并返回匹配项的集合。
例如,数字识别器可能会使用正则表达式,并将所有匹配的数字作为实体的集合返回。
长话短说,我们数据库中的每一项都将被视为一个单独的实体。这允许用户输入中包含实体,从而使我们能够创建更好的表达式。
用户姓名识别器
我们将不再从头创建实体识别器,而是创建一个利用CreateRecognizer重载方法,其第二个参数接受返回实体集合的函数。即EntityCollection.
将下列方法添加到MainWindow类。
private void CreateNameParser() { Bot.CreateRecognizer(“Name”, request => { var requestText = request.NormalizedText; var entities = new EntityCollection(); DatabaseUtility.Command.CommandText = “SELECT * FROM EMPLOYEES”; var reader = DatabaseUtility.Command.ExecuteReader(); while (reader.Read()) { var name = reader[“Name”].ToString(); var wordIndex = requestText.IndexOf(name, StringComparison.OrdinalIgnoreCase); if (wordIndex != -1) { var entity = new Entity(“Name”) { Value = name, Index = wordIndex }; entities.Add(entity); } } reader.Close(); return entities; }); }上面的代码创建了一个新的实体识别器。这个Name是我们希望在数据库中引用用户姓名的实体类型名称。
这个requestText保存用户请求文本的规范化值。规范化的值通常是相同的用户输入字符串,但是应用了过滤器。对此进行更多的讨论超出了本文的范围。
使用DatabaseUtility类中的所有项进行迭代。name我们数据库的列。然后,我们使用IndexOf方法,以查看用户输入中是否存在该值。如果返回的索引值不是-1,则会找到该单词。当名字创建一个新的类型实体name,并设置value的值为Index。
注:在Oscova中,所有实体都必须指定匹配值第一次出现的起始索引。
用户等级识别器
同样,我们还将为每个员工的等级创建一个实体识别器。但是,与上面的实体识别器不同,我们只创建一个空识别器,并使用Role列。
private void CreateRoleParser() { var parser = Bot.CreateRecognizer(“Role”); DatabaseUtility.Command.CommandText = “SELECT * FROM EMPLOYEES”; var reader = DatabaseUtility.Command.ExecuteReader(); while (reader.Read()) { var roleTitle = reader[“Role”].ToString(); if (parser.Entries.Contains(roleTitle)) continue; parser.Entries.Add(roleTitle); } reader.Close(); }现在,让我们从MainWindow构造函数将以下代码放置在//Parsers go here在构造器中的注释。
//Parsers go here CreateNameParser(); CreateRoleParser();如果到目前为止,我希望您已经对命名实体识别器有了基本的了解。
处理按钮和文本框事件
传递用户输入InputBox发送到Oscova进行Evaluate(评估),我们需要处理EvaluateButton.Click和InputBox.KeyDown事件。将下列代码添加到MainWindow类。
private void EvaluateButton_OnClick(object sender, RoutedEventArgs e) { var message = string.IsNullOrEmpty(InputBox.Text) ? “clear” : InputBox.Text; var result = Bot.Evaluate(message); ResultBox.Text = result.Serialize(); result.Invoke(); InputBox.Clear(); }上面的代码检查InputBox.Text价值是空的还是空的。如果为空,则Clear命令被发送进行评估。
在之后评价结果返回,我们设置ResultBox.Text属性保存序列化的JSON值,该值表示评价结果然后再调用Invoke方法执行方法。
private void InputBox_OnKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Return) { EvaluateButton_OnClick(null, null); } }上面的代码只在InputBox按动Enter键时调用EvaluateButton_OnClick方法。
创建对话框
到目前为止,我们一直在为我们的数据库机器人创建框架。现在跳出来,让我们开始实现基本dialog对话类。
dialog对话只是一个相关的集合指令集中在一起。你问我什么是指令?
指令是个指令!好吧,听起来可能不对。让我解释一下。指令是将用户输入映射到可执行操作。简单地说,在Oscova中,指令是一种在用户输入与表达式匹配时调用的方法。
Expression表达式另一方面,是一个模式或示例,取决于您如何编写它,类似于用户输入。
Oscova的评价系统将用户输入与所有输入进行比较执行。然后将表达式及其指令作为评价结果返回.
好了,代码老手,现在我们将创建我们的第一个对话框。
右键单击Solution Explorer,选择Add并选择New Folder 将文件夹命名为Dialogs 右击文件夹,选择Add并选择Class.. 给类命名DatabaseEnquiryDialog并选择Add.为了转换DatabaseEnquiryDialog对于一个Oscova对话框,您所要做的就是从Oscova的类中派生出Dialog类,如下所示。
class DatabaseEnquiryDialog: Dialog { }创造指令
我们的第一个指令是非常简单的。我们想要的是当用户说What is the age of Rick? (Rick(作为一个用户),我们希望聊天机器人返回相应的Age列。
我们会制定我们的指令PropertyEnquiry。为此,我们首先添加一个void方法的DatabaseEnquiryDialog类,如下所示。
public void PropertyEnquiry(Context context, Result result) { }以上代码的一些信息。
指令方法必须始终具有public访问权限。 指令可以采用0,1(上下文或结果)或2(上下文和结果)参数。 指令必须至少有一个表达式。接下来介绍。向指令中添加表达式
属性将表达式添加到指令的Expression属性。有两种主要的表达式类型:
示例表达式–我们只编写一个输入示例,并使用大括号对实体进行可选注释。 模板表达式–我们编写用户输入,而不是注释,而是正确地指定实体类型。示例表达式What is the age of Rick?看起来像:
[Expression(“What is the {age} of {Rick}?”)] [Entity(“property”)] [Entity(“name”)]第一Entity属性现在链接带注释的单词。age到实体类型property还有这个词Rick链接到实体类型name.
注:实体属性的顺序很重要,因为带注释的单词或短语的序列与Entity属性。
模板表达式What is the age of Rick?看起来像:
[Expression(“What is the @property of @name?”)]跟表达式不一样,模板表达式更容易编写,因为通过直接指定实体类型名称(以@为前缀)来避免注释。
为了本文,我们将添加一个example在我们的PropertyEnquiry方法中。
[Expression(“What is the {age} of {Rick}?”)] [Entity(“property”)] [Entity(“name”)] public void PropertyEnquiry(Context context, Result result) { }注:所有Oscova属性都可以在Syn.Bot.Oscova.Attributes命名空间。
现在,如果它什么也不做,它的指令又有什么用呢?这个指令必须为我们做两件事。
从数据库选择age栏Rick。 显示一条说明说明选择了这名用户为此,我们将在方法主体中添加以下内容:
public void PropertyEnquiry(Context context, Result result) { var name = result.Entities.OfType(“name”).Value; var property = result.Entities.OfType(“property”).Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.PropertyByName(name, property); result.SendResponse($”{property} of Employee \”{name}\”.”); }上面的代码首先获取property实体的name的匹配值。所有提取的实体都存储在Result.Entities。结果还发现,集合中的实体通常按用户输入中发生的顺序排列。
接下来,我们获取共享DatabaseUtility对象并调用PropertyByName方法。此方法通过选择指定的Employees表里面,其中员工的名称等于指定的namevalue值。
最后,通过调用Result.SendResponse方法传递文本响应。此响应,如MainWindow构造函数更改Value的ResponseLabel.
总体指令代码应该如下所示:
[Expression(“What is the {age} of {Rick}?”)] [Entity(“property”)] [Entity(“name”)] public void PropertyEnquiry(Context context, Result result) { var name = result.Entities.OfType(“name”).Value; var property = result.Entities.OfType(“property”).Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.PropertyByName(name, property); result.SendResponse($”{property} of Employee \”{name}\”.”); }测试指令
在我们继续测试指令我们需要把对话框添加到Oscova。在MainWindow构造函数就在注释下面。//Dialogs go here添加以下内容。
Bot.Dialogs.Add(new DatabaseEnquiryDialog());给你。现在按F5运行应用程序,并在输入框中输入:
What is the age of Rick?(Rick几岁了) What is the salary of Ahmed?(Ahmed的薪水多少)如果输出一样!那么你已经成功地创造了你的第一个指令。
注:中的值。表达,我们消除了为不同属性编写冗余表达式的需要。
在附带说明中,如果您单击JSON Result选项卡,您应该会看到评价结果.
{ “query”: “WHAT IS THE AGE OF RICK?”, “sessionId”: “78a8765f-3705-442d-a4ca-fe4dbd4c2e04”, “intents”: [ { “intent”: “DatabaseEnquiryDialog.PropertyEnquiry”, “score”: 0.9985714285714286 }, { “intent”: “DatabaseEnquiryDialog.EmployeeName”, “score”: 0.59047619047619047 } ], “entities”: [ { “entity”: “AGE”, “type”: “property” }, { “entity”: “Rick”, “type”: “Name” } ], “contexts”: [] }注:在不同的机器人设置中,指令的分数可能会有所不同。
更多指令
在我们进入下一个创建上下文意图的阶段之前。我们将继续增加一些指令表达式。
输入模式的意图:What is the salary of the CEO?(CEO薪水多少)
[Expression(“What is the @property of @role”)] [Expression(“@property of @role”)] public void PropertyByRole(Context context, Result result) { var role = result.Entities.OfType(“role”).Value; var property = result.Entities.OfType(“property”).Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.PropertyByRole(role, property); result.SendResponse($”{property} of \”{role}\”.”); }输入指令模式:Who is Wang?
[Expression(“Find employee with the name @name”)] [Expression(“Who is @name?”)] public void EmployeeName(Context context, Result result) { var name = result.Entities.OfType(“name”).Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.EmployeeByName(name); result.SendResponse($”Employee(s) with the name {name}.”); }输入指令模式:Who is the admin?
[Expression(“Find employee whose role is @role”)] [Expression(“Who is the @role?”)] public void EmployeeRole(Context context, Result result) { var role = result.Entities.OfType(“role”).Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.EmployeeByRole(role); result.SendResponse($”Employee(s) with job role \”{role}\”.”); }语境指令
在本节中,我们将学习两个新概念。
语境指令 使用预先构建的系统实体。尽管Oscova附带了数十个预先构建的系统实体,但我们将只使用其中的两个。
右键单击Dialogs文件夹,选择Add并选择Class.. 给类命名DatabaseUpdateByNameDialog并选择Add.就像前面的对话框一样,派生出DatabaseUpdateByNameDialog从基地Dialog类,如下所示。
class DatabaseUpdateByNameDialog : Dialog { }此对话框中的意图结构如下:
允许用户更改员工财产价值(年龄、薪资)的意图 确定指令:如果用户说Yes提交对数据库的更改。 取消指令:如果用户说No提交操作被取消。什么是语境?
上下文是表示用户输入的当前上下文的字符串值。在Oscova,上下文有名字和寿命。生命周期通常是上下文将持续的请求数。
为了更好的处理常量字符串值。我们将首先创建一个静态类来保存一个常量字符串值,我们将使用该值作为上下文项的名称。
向项目中添加一个新类并命名它DatabaseContext.
static class DatabaseContext { public const string ConfirmUpdateByName = “ConfirmUpdateByName”; }现在,允许用户对数据库进行更改的第一个指令。双击DatabaseUpdateByNameDialog.cs并添加以下代码。
[Expression(“@set @property of @name to @sys.number”)] public void ChangePropertyOfName(Context context, Result result) { context.Add(DatabaseContext.ConfirmUpdateByName); var property = result.Entities.OfType(“property”); var name = result.Entities.OfType(“name”); var number = result.Entities.OfType<NumberEntity>(); context.SharedEntities.Add(property); context.SharedEntities.Add(name); context.SharedEntities.Add(number); var propertyString = property.Value.ToLower(); if (propertyString != “age” && propertyString != “salary”) { result.SendResponse($”{property} of {name} is readonly.”); return; } result.SendResponse($”Are you sure that you want to change {property} of {name} to {number}?”); }这个Expression在上面的代码中,启用以下命令:
Change the age of Mark to 43(改变Mark的年龄为43) Set the salary of Krishna to 17000(设置Krishna的工资为17000)在模板表达式中,值@sys.number与数字匹配的系统实体类型。有大量的系统实体可供开发人员使用。您可以阅读Oscova的API文档以获得更多细节。
注意context.Add(DatabaseContext.ConfirmUpdateByName);,通过将字符串值添加到上下文中,Bot在其下一个请求中将首先搜索指定上下文中的指令。
因为在下一次指令调用时,结果如果被清除,我们将使用Context.SharedEntities属性将当前实体传递给下一个指令。
最后,当用户发送上述命令时,我们向用户发送一个请求确认的响应。
我们处理问题的方式来自用户的后续响应No。为此,我们将创建一个指令,如下所示。
[Expression(“{no}”)] [Entity(Sys.Negative)] [Context(DatabaseContext.ConfirmUpdateByName)] public void ChangePropertyByNameDeclined(Context context, Result result) { context.SharedEntities.Clear(); result.SendResponse(“Operating canceled.”); }在上面的意图中有两件事需要注意。
第一[Entity(Sys.Negative)]..Entity属性指定类型的系统实体。@sys.negative哪个匹配no 诸若此类。类的常量字段可以找到所有实体类型。Sys类。
第二,[Context(DatabaseContext.ConfirmUpdateByName)]显式指定此意图仅在ConfirmUpdateByName背景。
我们创造了以下指令,用来响应来自用户的后续响应yes。
[Expression(“{Yes}”)] [Entity(Sys.Positive)] [Context(DatabaseContext.ConfirmUpdateByName)] public void ChangePropertyConfirmed(Context context, Result result) { var property = context.SharedEntities.OfType(“property”); var name = context.SharedEntities.OfType(“name”).Value; var number = context.SharedEntities.OfType<NumberEntity>().Value; var utility = context.SharedData.OfType<DatabaseUtility>(); utility.UpdatePropertyByName(name, property.Value, number.ToString(CultureInfo.InvariantCulture)); result.SendResponse($”{property} of {name} changed to {number}”); context.SharedEntities.Clear(); }上述意图的表达式注释yes作为@sys.positive实体类型来捕获积极的后续响应。就像ChangePropertyByNameDeclined我们指定上述指令也必须在ConfirmUpdateByName下面。
在方法体中,我们首先检索之前添加到SharedEntities集合并将值传递给DatabaseUtility.UpdatePropertyByName函数。
提交完成后,我们发送一个文本响应,说明已进行所请求的更改,并清除SharedEntities收藏。
如果用户说yes或者类似的更改将被提交到Employees数据库。
检验指令
我们将重复对前一个对话框所做的操作,并添加DatabaseUpdateByNameDialog到Bot.Dialogs将下列代码放置在//Dialogs go here在MainWindow构造函数
Bot.Dialogs.Add(new DatabaseUpdateByNameDialog());按下F5发送指令Change the salary of Vincent to 24000(将Vincent的薪金改为24000).
如果一切顺利,应向你提出以下问题
Are you sure you want to change the salary of Vincent to 24000?(你确定你想把Vincent的薪水改为24000吗?)
如果你说yes更改将被传递到数据库,否则操作将被取消。
好吧,这就是所有的内容。谢谢你的阅读!
有问题还是反馈?在评论中让我知道。
免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:使用Oscova的数据库的聊天机器人 https://www.yhzz.com.cn/a/13543.html