今日闲来无事,脑洞大开,决定写一个聊天机器人。
当然,我们去自己实现人工智能的聊天对话功能是不现实了,即使去做,也要花费大量的时间精力,最后可能也搞不出来。于是,从网上搜索相关的API接口,于是,找到了这个:http://www.tuling123.com/openapi/
感觉虽然和微软的小冰和韩国的小黄鸡还有些差距,不过也还好,就这样吧。
先上效果图(比较丑。。。)
图灵机器人API的使用非常简单,用一个http的get形式获取,就会返回一个json数据,再解析json数据即可
举例说来就是:
如果发送过去这个:
请求示例: http://www.tuling123.com/openapi/api?key=KEY&info=你漂亮么
其中的KEY是在注册图灵API的时候提供给你的
那么返回的就是这样的一个json数据:
{
"code":100000,
"text":"恩恩,害羞ing……"
}
很简单的样子...下面开始着手去做了
首先,把要解决的问题罗列出来:
1,使用什么工具编写
2,如何使用http get
3,如何解析json数据
下面逐一解决:
问题一:使用什么工具编写
最初打算使用python来着,简单易用,还可以跨平台。
但是吧。。。由于图灵API返回的数据是utf-8编码的,Python对于utf-8编码的转换很复杂,总是报错,上网查询好久无果,只好退而求其次,使用C#编写吧。
(没使用C和C++主要是界面描画很麻烦,C本身描画界面就需要借助第三方的东西,C++用MFC感觉太复杂了。Java学的不好。。。)
问题二:怎么使用Http get
参考如下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
namespace HttpGetter
{
class Program
{
static void Main(string[] args)
{
String url = "http://www.csdn.net"; //设定要get的地址
Encoding encoding = Encoding.GetEncoding("utf-8"); //设定编码格式
String data = HttpGet(url, encoding);
if (data != "")
{
Console.WriteLine(data);
}
Console.ReadLine();
}
public static string HttpGet(string url, Encoding encoding)
{
string data = "";
try
{
WebRequest request; //使用url发出请求的类
request = WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials; //使用默认的身份验证
request.Timeout = 10000; //设定超时
WebResponse response; //提供响应的类
response = request.GetResponse();
data = new StreamReader(response.GetResponseStream(), encoding).ReadToEnd(); //获取数据
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
return data;
}
}
}
上面的代码是在C#命令行中运行的,之后会制造一个界面,做成一个窗口形式的程序
问题三:如何解析json数据
这个问题搞得很头大,C#自带的json解析感觉比较复杂,玩不转。只好下载了一个第三方的json解析工具:Newtonsoft.Json
安装这个很简单,但是如果网络不好,会出现下载失败的问题
以我使用的VS2013为例,
工具 -> NuGet程序包管理器 -> 程序包管理器控制台
之后再出现的控制台上输入这个:
install-package newtonsoft.json
之后,如果之前没下载过得话,会联网进行下载,下载完成之后,就可以使用Newtonsoft.Json的工具类了
下面开始编码吧
界面的实现,就是两个Textbox,一个按钮,和一个图片框。
一个TextBox作为输入框,一个作为聊天记录的现实,按钮作为提交按钮,图片框里放一张你喜欢的机器人头像就好(哆啦A梦,阿童木,阿拉蕾随意。。。)
可能需要调整的细节有:
聊天记录的TextBox不允许用户输入,所以ReadOnly属性要置为True
软件希望按下回车能够自动提交输入内容,所以,窗体的AcceptButton要设定为窗体上的那个按钮。
想要正常的与机器人交流,必须要遵循机器人的规则,这里要按照如下格式进行对话的提交:
http://www.tuling123.com/openapi/api?key=KEY&info=TEXT
上面的KEY是在注册图灵机器人账号的时候得到的,是一串很长的数字加字母
TEXT是你的问话内容
Newtonsoft提供的JSON解析器还是比较容易使用的。(要using Newtonsoft.Json;)
首先,用一个String类型的变量存放要解析的Json数据,之后,创建Json解析类
JsonReader reader = new JsonTextReader(new StringReader(data));
之后,调用reader.Read()进行解析。
每一次read,都取得了这一次解析的内容,
比如:
你输入“你好”,
得到的Json数据为:{"code":100000,"text":"你好啊,希望你今天过的快乐"}
在控制台程序中重复执行:
Console.WriteLine(reader.TokenType + "\t\t" + reader.ValueType + "\t\t" + reader.Value);
reader.Read();
得到的输出为:
StartObject
PropertyName System.Stringcode
Integer System.Int64100000
PropertyName System.Stringtext
String System.String你也好 嘻嘻
EndObject
参考官网提供的文档,如果返回码code为100000,则表明这是一个文本数据,text是返回的对话内容
图灵API还提供了诸如航班电影等一系列的返回形式,原理基本相同,这里只实现对于文本类型返回值的处理。
根据这个规则,就可以写一个很傻的解析程序:
while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName
&& reader.ValueType == Type.GetType("System.String")
&& Convert.ToString(reader.Value) == "code")
{
/* 如果当前Value是code,读取下一条,查看code的值 */
reader.Read();
switch (Convert.ToInt32(reader.Value))
{
case 100000:
/* 返回码为文本类数据 */
reader.Read();
reader.Read();
tbxHistory.AppendText("Robot: " + reader.Value + "\n");
break;
default:
break;
}
}
}
中间两个reader.Read();是用来跳过text标示的那一次数据,这里只是节约时间,后期可以根据官方文档做一个解析更全面,更安全的程序。
基本差不多了,最终附上所有代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;//json解析用
using System.IO;
using System.Net;
namespace ChatRobot
{
public partial class ChatRobotForm : Form
{
const String KEY = "XXXXXXXXXXXXXXXXXXXXX"; //这里是注册时得到的key
public ChatRobotForm()
{
InitializeComponent();
}
private void btnCommit_Click(object sender, EventArgs e)
{
String input = tbxInput.Text;
string url = "http://www.tuling123.com/openapi/api?key=" + KEY + "&info=" + input;
/* 清空输入框 */
tbxInput.Text = "";
/* 将输入内容放入聊天记录窗口中 */
tbxHistory.AppendText("You: " + input + "\n");
Encoding encoding = Encoding.GetEncoding("utf-8");
String data = HttpGet(url, encoding);
JsonReader reader = new JsonTextReader(new StringReader(data));
while (reader.Read())
{
//tbxHistory.AppendText(reader.TokenType + "\t\t" + reader.ValueType + "\t\t" + reader.Value + "\n");
if (reader.TokenType == JsonToken.PropertyName
&& reader.ValueType == Type.GetType("System.String")
&& Convert.ToString(reader.Value) == "code")
{
/* 如果当前Value是code,读取下一条,查看code的值 */
reader.Read();
switch (Convert.ToInt32(reader.Value))
{
case 100000:
/* 返回码为文本类数据 */
reader.Read();
reader.Read();
tbxHistory.AppendText("Robot: " + reader.Value + "\n");
break;
default:
break;
}
}
}
}
public static string HttpGet(string url, Encoding encoding)
{
string data = "";
try
{
WebRequest request; //使用url发出请求的类
request = WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials; //使用默认的身份验证
request.Timeout = 10000; //设定超时
WebResponse response; //提供响应的类
response = request.GetResponse();
data = new StreamReader(response.GetResponseStream(), encoding).ReadToEnd(); //获取数据
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
return data;
}
}
}
namespace ChatRobot
{
partial class ChatRobotForm
{
///
/// 必需的设计器变量。
///
private System.ComponentModel.IContainer components = null;
///
/// 清理所有正在使用的资源。
///
/// 如果应释放托管资源,为 true;否则为 false。
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
///
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChatRobotForm));
this.btnCommit = new System.Windows.Forms.Button();
this.tbxInput = new System.Windows.Forms.TextBox();
this.tbxHistory = new System.Windows.Forms.TextBox();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// btnCommit
//
this.btnCommit.Location = new System.Drawing.Point(303, 290);
this.btnCommit.Name = "btnCommit";
this.btnCommit.Size = new System.Drawing.Size(118, 27);
this.btnCommit.TabIndex = 0;
this.btnCommit.Text = "确定";
this.btnCommit.UseVisualStyleBackColor = true;
this.btnCommit.Click += new System.EventHandler(this.btnCommit_Click);
//
// tbxInput
//
this.tbxInput.Location = new System.Drawing.Point(12, 216);
this.tbxInput.Multiline = true;
this.tbxInput.Name = "tbxInput";
this.tbxInput.Size = new System.Drawing.Size(409, 68);
this.tbxInput.TabIndex = 1;
//
// tbxHistory
//
this.tbxHistory.Location = new System.Drawing.Point(109, 9);
this.tbxHistory.Multiline = true;
this.tbxHistory.Name = "tbxHistory";
this.tbxHistory.ReadOnly = true;
this.tbxHistory.Size = new System.Drawing.Size(311, 194);
this.tbxHistory.TabIndex = 2;
//
// pictureBox1
//
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(12, 12);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(91, 87);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureBox1.TabIndex = 3;
this.pictureBox1.TabStop = false;
//
// ChatRobotForm
//
this.AcceptButton = this.btnCommit;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(433, 329);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.tbxHistory);
this.Controls.Add(this.tbxInput);
this.Controls.Add(this.btnCommit);
this.Name = "ChatRobotForm";
this.Text = "聊天机器人";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button btnCommit;
private System.Windows.Forms.TextBox tbxInput;
private System.Windows.Forms.TextBox tbxHistory;
private System.Windows.Forms.PictureBox pictureBox1;
}
}
好了,代码很短,只有不到100行,还是有很多功能有待实现,后续还会不断改进的(如果有时间的话。。。)