在Unity中实现聊天机器人

恬静的小魔龙 2020-12-10 18:35:14 9084

在这篇文章中,我们将在Unity中集成一个可以离线工作的聊天机器人开发框架。

我们将首先创建聊天界面,然后将其绑定到Oscova来实现机器人的智能对话。然后我们将在我们的机器人上创建一个简单的“Hello Bot”对话框,看看如何在Unity中生成和显示我们的响应。

导言

我们将直接集成聊天机器人到Unity中方式,这意味着我们可以离线运行聊天程序,而不是调用一些在线API来为用户生成响应消息,不必依赖任何在线服务或订阅来生成智能响应。为此,我们将使用一个流行的基于设备的机器人开发工具oscova,来创建一个简单的“Hello Bot”对话框测试聊天机器人。

安装Unity

如果还没有安装Unity:

创建Unity项目

  • 通过选择3D项目模板,启动Unity并创建一个新的3D项目。

  • 您可以将项目命名为

MyFirstUnityBot

  • 单击Create纽扣。

创建聊天机器人UI

我们需要三个重要的UI元素来创建我们在UnityChatbot界面。

  • 显示面板-所有聊天/信息都将在那里举行
  • 输入栏-用户输入内容的地方
  • 发送按钮-用户将按下按钮提交他的信息

要创建我们的显示系统:

  • 右击Hierarchy窗口,选择UI选择Canvas.

  • 选中Canvas,右键单击,选择UI选择Scroll View.

  • 设置控件的宽度500和高度300。

生成用户或bot消息后,我们需要将该消息添加到Scroll View。为此,我们将创建文本UI元素的预制件,并在将消息添加到Scroll View时使用它。

  • 点击Content
  • 添加Content Size Filter组件
  • 添加Vertical Layout Group组件

  • 再次点击Content,选择创建Text
  • 设置Text定位到左下角,将字体大小设置为16
  • Vertifical Overflow选择Overflow
  • 将text拖入到项目视图中,制作成一个预制体,并在Hierarchy视图中删除它

创建一个新的Input Field和一个Button并排放置,如下所示。我们将使用这两个UI元素向我们的机器人发送用户消息。

导入OSCOVA-Syn Bot框架

与我们在C#项目中导入库的方式不同,比如通过NuGet导入库,每次修改脚本时都会重新编译Unity项目,因此我们不能简单地在这里使用NuGet包。相反,我们将处理一个包含框架库及其依赖项的UnityPackage。

下载Syn.Bot统一包.

  • 右击Assets,选择Import Package选择Custom Package.
  • 当导入窗口出现时,请确保选择了包中的所有项。
  • 点击Import.

编写Bot接口脚本

为了将UI元素绑定到我们的bot中,我们现在继续编写它的脚本。

  • 在层次窗口创建一个Empty Object命名GameManager
  • 创建Script组件,并将其命名为GameManager
  • 双击新添加的GameManager的脚本。
  • 这将打开VisualStudio项目。

记住Message对象中添加Scroll View?那么,让我们创建一个类,它将保存用户和bot消息,并使我们能够通过Text预制件。

这个Message类将将用户/bot消息保存为string,引用Text预制件和可选的aMessageType枚举,这将帮助我们用不同的颜色来装饰信息。

using Syn.Bot.Oscova;
using Syn.Bot.Oscova.Attributes;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Message
{
    public string Text;
    public Text TextObject;
    public MessageType MessageType;
}

public enum MessageType
{
    User, Bot
}

public class GameManager : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

现在消息持有者已经准备好了,我们将继续创建一些公共字段,我们将从内部统一绑定到其中。我们还将创建一个OscovaBot对象,该对象将在游戏运行时实例化。将代码放置在Start()方法。

OscovaBot MainBot;

List<Message> Messages = new List<Message>();

public GameObject chatPanel, textObject;
public InputField chatBox;
public Color UserColor, BotColor;

保存VisualStudio项目,并在层次窗口中选择GameManager。我们现在将字段与它们各自的组件连接起来。

  • 设置Chat Panel对象为Content
  • Text ObjectText预制体
  • Chat Box字段到Input Field

我们创建了一个MessageType属性中的Message类,以便用户能够在视觉上区分这两者。将用户和Bot颜色对象值设置为您选择的值,但请记住将Alpha值设置为255,以使其保持可见。

显示用户/Bot消息

控件中显示用户和bot消息。Scroll View属性的内容,我们将不得不在它的转换中定位对象。另外,我们将为每种消息类型指定一个颜色。

在下面的代码中,我们创建了Message类的转换中,将消息字符串分配给它,并实例化它。chatPanel。名单Messages用于对邮件计数进行检查。如果计数超过25,我们就移除25TH最后一项。最后,基于MessageType,我们为text.<text>.

public void AddMessage(string messageText, MessageType messageType)
{
    if (Messages.Count >= 25)
    {
        //Remove when too much.
        Destroy(Messages[0].TextObject.gameObject);
        Messages.Remove(Messages[0]);
    }

    var newMessage = new Message { Text = messageText };

    var newText = Instantiate(textObject, chatPanel.transform);

    newMessage.TextObject = newText.GetComponent<Text>();
    newMessage.TextObject.text = messageText;
    newMessage.TextObject.color = messageType == MessageType.User ? UserColor : BotColor;

    Messages.Add(newMessage);
}

处理用户消息

在我们的下一个方法中,我们将创建一个逻辑,它将控制用户向Bot发布消息后发生的事情。长话短说,我们将把信息发送给机器人进行处理。我们称之为这种方法SendMessageToBot().

public void SendMessageToBot()
{
    var userMessage = chatBox.text;

    if (!string.IsNullOrEmpty(userMessage))
    {
        Debug.Log($"OscovaBot:[USER] {userMessage}");
        AddMessage($"User: {userMessage}", MessageType.User);        
        var request = MainBot.MainUser.CreateRequest(userMessage);
        var evaluationResult = MainBot.Evaluate(request);
        evaluationResult.Invoke();

        chatBox.Select();
        chatBox.text = "";
    }
}

在上面的方法中,我们首先从Input Field属性。然后检查消息是否为空字符串。

接下来,我们使用用户消息创建一个用户请求,获取评估结果并调用Invoke()方法。这将迫使Bot选择最高匹配意图并执行它。哪个转弯处将生成一个响应,我们稍后将为该响应添加一个事件处理程序。

在最后一部分中,我们只选择Input Field (chatBox)并通过将其文本值设置为空字符串来清除其内容。

连接到按钮单击

SendMessageToBot()方法时,需要在用户单击Send按钮或按键Enter在输入字段中。

  • 选择层次结构中的Button按钮。
  • On Click(),选择GameManager
  • GameManager对象中,选择SendMessageToBot().

连接到按钮点击

除了处理用户消息以外,当Send按钮,我们还需要在用户点击时处理用户消息。Enter在输入字段中。要做到这一点,我们只需更改Update()方法:

void Update
{
 if (Input.GetKeyDown(KeyCode.Return))
    {
        SendMessageToBot();
    }
}

简单Hello Bot对话

我们使用Oscova来构建机器人的知识库(KB)。您可以通过Oryzer Studio或直接用纯c#代码在SIML、Syn工作区中创建KB。为了简单和避免文章过于冗长,我们将在脚本中直接用c#创建一个简单的对话框。

我们首先创建一个BotDialog类继承Dialog类中,我们将在其中创建一个void Hello()方法,并将其装饰为Expression属性,其中我们将将示例用户消息指定为Hello Bot。然后,此方法将返回Hello User!作为机器人的回应。

public class BotDialog: Dialog
{
    [Expression("Hello Bot")]
    public void Hello(Context context, Result result)
    {
        result.SendResponse("Hello User!");
    }
}

如果上面的代码没有多大意义,那是因为有一些概念您必须熟悉。

现在我已经向您提示了进一步学习的正确方向,让我们继续更新我们的Start()方法将其全部包装起来。

初始化Bot实例

我们得把几样东西放在一起才能让我们的机器人工作。首先,我们需要实例化我们的bot对象,然后我们需要处理当bot生成响应时发生的事情。

在我们的代码中,我们创建了OscovaBot并将其分配给MainBot场。然后,我们添加以前创建的BotDialogDialogs收集机器人并开始培训。最后,我们将事件处理程序添加到ResponseReceived事件。它只会调用AddMessage()具有机器人响应的方法。

void Start()
{
    try
    {
        MainBot = new OscovaBot();
        OscovaBot.Logger.LogReceived += (s, o) =>
        {
            Debug.Log($"OscovaBot: {o.Log}");
        };

        MainBot.Dialogs.Add(new BotDialog());
        MainBot.Trainer.StartTraining();

        MainBot.MainUser.ResponseReceived += (sender, evt) =>
        {
            AddMessage($"Bot: {evt.Response.Text}", MessageType.Bot);
        };
    }
    catch (Exception ex)
    {
        Debug.LogError(ex);
    }
}

我们已经完成了编码!

总体代码

如下所示:

using Syn.Bot.Oscova;
using Syn.Bot.Oscova.Attributes;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Message
{
    public string Text;
    public Text TextObject;
    public MessageType MessageType;
}

public enum MessageType
{
    User, Bot
}

public class BotDialog: Dialog
{
    [Expression("Hello Bot")]
    public void Hello(Context context, Result result)
    {
        result.SendResponse("Hello User!");
    }
}

public class GameManager : MonoBehaviour
{
    OscovaBot MainBot;

    public GameObject chatPanel, textObject;
    public InputField chatBox;

    public Color UserColor, BotColor;

    List<Message> Messages = new List<Message>();

    // Start is called before the first frame update
    void Start()
    {
        try
        {
            MainBot = new OscovaBot();
            OscovaBot.Logger.LogReceived += (s, o) =>
            {
                Debug.Log($"OscovaBot: {o.Log}");
            };

            MainBot.Dialogs.Add(new BotDialog());
            //MainBot.ImportWorkspace("Assets/bot-kb.west");
            MainBot.Trainer.StartTraining();

            MainBot.MainUser.ResponseReceived += (sender, evt) =>
            {
                AddMessage($"Bot: {evt.Response.Text}", MessageType.Bot);
            };
        }
        catch (Exception ex)
        {
            Debug.LogError(ex);
        }
    }

    public void AddMessage(string messageText, MessageType messageType)
    {
        if (Messages.Count >= 25)
        {
            //Remove when too much.
            Destroy(Messages[0].TextObject.gameObject);
            Messages.Remove(Messages[0]);
        }

        var newMessage = new Message { Text = messageText };

        var newText = Instantiate(textObject, chatPanel.transform);

        newMessage.TextObject = newText.GetComponent<Text>();
        newMessage.TextObject.text = messageText;
        newMessage.TextObject.color = messageType == MessageType.User ? UserColor : BotColor;

        Messages.Add(newMessage);
    }

    public void SendMessageToBot()
    {
        var userMessage = chatBox.text;

        if (!string.IsNullOrEmpty(userMessage))
        {
            Debug.Log($"OscovaBot:[USER] {userMessage}");
            AddMessage($"User: {userMessage}", MessageType.User);
            var request = MainBot.MainUser.CreateRequest(userMessage);
            var evaluationResult = MainBot.Evaluate(request);
            evaluationResult.Invoke();

            chatBox.Select();
            chatBox.text = "";
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Return))
        {
            SendMessageToBot();
        }
    }
}

测试机器人

不需要进一步的介绍了,让我们保存VisualStudio项目,以便Unity编译和提交更改。

运行游戏,输入消息然后按下Send按钮。瞧!你的机器人的反应在你的屏幕上。

总结

哎呀!这是一个有趣的项目。

游戏平台上的聊天机器人打开了许多新的大门。看到开发者将在他们的游戏中构建什么,以及智能聊天机器人将如何改变游戏体验,这将是令人兴奋的。

为了减少冗余,我避免为机器人创建更大的知识库。然而,游戏环境中的聊天机器人需要更多有趣的对话需要去添加。

源代码下载链接

MyUnityBot.zip

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 95 7 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
恬静的小魔龙
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区