[UNIT] C#利用API调用UNIT
goJhou 发布于2017-10 浏览:40539 回复:55
7
收藏

以下是类内的静态变量。用于管理状态及TOKEN信息,SESSION信息。

// 调用getAccessToken()获取的 access_token建议根据expires_in 时间 设置缓存
        // 返回token示例
        public static readonly String TOKEN = getAccessToken();

        public static bool IsFinishedThisUnit;
        private static string sessionId="";
        private static bool first=true;

下面是一段 c#调用百度API接口,获取临时token值。

public static string getAccessToken()
        {
            String clientId = 【这里填入APPID】;
            String clientSecret = 【这里填入APPSECRET】;
            String authHost = "https://aip.baidubce.com/oauth/2.0/token";
            HttpClient client = new HttpClient();
            List> paraList = new List>();
            paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
            paraList.Add(new KeyValuePair("client_id", clientId));
            paraList.Add(new KeyValuePair("client_secret", clientSecret));

            HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
            String result = response.Content.ReadAsStringAsync().Result;
            //Console.WriteLine(result);
            JObject res = JObject.Parse(result);
            return res["access_token"].ToString();
        }

再根据TOKEN调用UNIT通用API接口获取返回json字符串并分析字符串指向的方法

public static JObject Unit_Send(string Content)
        {
            IsFinishedThisUnit = false;
            string host = "https://aip.baidubce.com/rpc/2.0/solution/v1/unit_utterance?access_token=" + TOKEN;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
            request.Method = "post";
            request.ContentType = "application/json";
            request.KeepAlive = true;
            string str = "{\"scene_id\":【这里填入UNIT场景ID】,\"query\":\"" + Content + "\", \"session_id\":\"" + sessionId + "\"}"; // json格式
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            JObject res = JObject.Parse(reader.ReadToEnd());
            if (res["error_code"] == null)
            {
                sessionId = res["result"]["session_id"].ToString();
                if (res["result"]["action_list"][0]["action_type"]["act_type"].ToString() == "satisfy")
                {
                    //意图完成
                    IsFinishedThisUnit = true;
                    return res;
                }
                else if (res["result"]["action_list"][0]["action_type"]["act_type"].ToString() == "clarify")
                {
                    //意图未完成
                    Console.Write(res["result"]["action_list"][0]["say"].ToString());
                    return null;
                }
                else
                {
                    //未知意图 可加本地日志记录逻辑 以后期扩充样本集
                    Console.Write("你到底想干嘛?");
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
    }
收藏
点赞
7
个赞
共55条回复 最后由用户已被禁言回复于2022-04
#16goJhou回复于2017-11
#14 一个秂的黑聿白回复
大神,这个sessionid指的一次会话是不是就是一次问答,而不是直到一个意图完成,获取答复?就是我提问后,sessionid从空变成了返回的一个值1,我们接着对话,sessionid又会改变,变成值2,再对话,还会改变?
展开

单次会话指的是  服务器与客户端的一次稳定连接时长。UNIT的会话长短由客户端应用层控制  并不是某次意图完成为一次会话

1
#15goJhou回复于2017-11
#14 一个秂的黑聿白回复
大神,这个sessionid指的一次会话是不是就是一次问答,而不是直到一个意图完成,获取答复?就是我提问后,sessionid从空变成了返回的一个值1,我们接着对话,sessionid又会改变,变成值2,再对话,还会改变?
展开

session可以一直保存下去,不会变的。不用担心每次赋值会改变。

他第一轮会返回sessionID,之后你只要坚持用sessionID进行请求,他这个是不会变的。

除非你再次以空session请求,他会开一个新会话,返回给你新的sessionID。

使用sessionID的好处是可以获取上一轮会话填充的词槽情况(词槽继承、复用词槽)。如果开了新会话就都没了。

1
#14一个秂的黑聿白回复于2017-11

大神,这个sessionid指的一次会话是不是就是一次问答,而不是直到一个意图完成,获取答复?就是我提问后,sessionid从空变成了返回的一个值1,我们接着对话,sessionid又会改变,变成值2,再对话,还会改变?

0
#13goJhou回复于2017-11
#12 一个秂的黑聿白回复
感谢大佬!!!

互相学习,客气客气

1
#12一个秂的黑聿白回复于2017-11

感谢大佬!!!

0
#11ZYuXinz回复于2017-11

这个就挺好的! 之前没看到!

0
#10goJhou回复于2017-11
#9 笔墨哥回复
好棒哒初心呀~

= =~~~

1
#9笔墨哥回复于2017-11
#8 goJhou回复
不不不 就是满基础的东西  节约大家开发时间

好棒哒初心呀~

0
#8goJhou回复于2017-11
#7 笔墨哥回复
专业级别的,厉害~

不不不 就是满基础的东西  节约大家开发时间

1
#7笔墨哥回复于2017-11

专业级别的,厉害~

0
#6goJhou回复于2017-10
#5 荒墨丶迷失回复
支持兄弟hhhhhhhh~

谢谢谢谢

1
#5荒墨丶迷失回复于2017-10

支持兄弟hhhhhhhh~

1
#4kohakuarc回复于2017-10

膜拜大佬~~~感觉大佬的无偿奉献

1
#3goJhou回复于2017-10

这里给大家分享几个 我在示例中用到的会调用到的单参方法,和无参实体方法,供大家参考

setBright:

/// 
        /// 设置亮度
        /// 
        /// 0~100
        public void setBright(int brightValue)
        {
            string functionName = "set_bright";
            if (this.support.Contains(functionName) && brightValue >= 0 && brightValue <= 100)
            {
                ArrayList aL = new ArrayList();
                aL.Add(brightValue);
                aL.Add("smooth");
                aL.Add(500);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if ((string)res["result"][0] == "ok")
                {
                    Console.WriteLine("操作完成");
                }
            }
            else
            {
                if (!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }
                else
                {
                    Console.WriteLine("亮度值应该在0~100之间");
                }
            }
        }

setRGB:

/// 
        /// 设置RGB
        /// 
        /// (R*65536+G*256+B)
        public void setRGB(int rgbValue)
        {
            string functionName = "set_rgb";
            if (this.support.Contains(functionName) && rgbValue >= 0 && rgbValue <= 16777215)
            {
                ArrayList aL = new ArrayList();
                aL.Add(rgbValue);
                aL.Add("smooth");
                aL.Add(500);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if ((string)res["result"][0] == "ok")
                {
                    Console.WriteLine("操作完成");
                }
            }
            else
            {
                if (!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }
                else
                {
                    Console.WriteLine("RGB值应该在0~16777215之间");
                }
            }
        }

setCtAbx:

/// 
        /// 设置色温
        /// 
        /// 
        public void setCtAbx(int ctvalue)
        {
            string functionName = "set_ct_abx";
            if (this.support.Contains(functionName) && ctvalue >= 1700 && ctvalue <= 6500)
            {
                ArrayList aL = new ArrayList();
                aL.Add(ctvalue);
                aL.Add("smooth");
                aL.Add(500);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if((string)res["result"][0]=="ok")
                {
                    Console.WriteLine("操作完成");
                }
            } else
            {
                if(!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }else
                {
                    Console.WriteLine("色温合法值在1700~6500K之间");
                }
            }
        }

 

AddCron:

/// 
        /// 设置定时关闭
        /// 
        /// 
        public void AddCron(int minutes)
        {
            string functionName = "cron_add";
            if (this.support.Contains(functionName))
            {
                ArrayList aL = new ArrayList();
                aL.Add(0);
                aL.Add(minutes);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if ((string)res["result"][0] == "ok")
                {
                    Console.WriteLine("操作完成");
                }
            }
            else
            {
                if (!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }
            }
        }

 

 

无参方法:

/// 
        /// 打开灯光
        /// 
        public void open()
        {
            string functionName = "set_power";
            if (this.support.Contains(functionName))
            {
                ArrayList aL = new ArrayList();
                aL.Add("on");
                aL.Add("smooth");
                aL.Add(500);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if ((string)res["result"][0] == "ok")
                {
                    Console.WriteLine("操作完成");
                }
            }
            else
            {
                if (!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }
            }
        }

 

/// 
        /// 关闭灯光
        /// 
        public void close()
        {
            string functionName = "set_power";
            if (this.support.Contains(functionName))
            {
                ArrayList aL = new ArrayList();
                aL.Add("off");
                aL.Add("smooth");
                aL.Add(500);
                JObject res = JObject.Parse(SendMessage(functionName, JsonConvert.SerializeObject(aL)));
                if ((string)res["result"][0] == "ok")
                {
                    Console.WriteLine("操作完成");
                }
            }
            else
            {
                if (!this.support.Contains(functionName))
                {
                    Console.WriteLine("该灯不支持 " + functionName + " 操作");
                }
            }
        }

 

因为该场景示例是用UDP协议与硬件交互的。交互过程封装在了SendMessage方法中,这个方法就不公开了,各位可以忽略这个方法。

0
#2goJhou回复于2017-10

在分析了UNIT返回的json字符串之后,我们要将词槽的值 分类别存放到内存中。如下是我自己封装的所谓的词槽解析方法

是针对我自己的应用场景的,分享给大家,可自行修改代码以提高场景适配度

public static void DoSth(JObject obj)
        {
            if (obj == null)
            {
                Console.Write("意图有错误");
                return;
            }                
            List< string> target =new List() ;
            List place =new List();
            int value=0;
            string MethodName = obj["result"]["action_list"][0]["main_exe"].ToString();
            lastMethod = MethodName;
            foreach(var item in obj["result"]["schema"]["bot_merged_slots"])
            {
                switch(item["type"].ToString())
                {
                    case "user_target"://这都是我的词槽名字
                        target.Add(item["normalized_word"].ToString());
                        break;

                    case "user_place"://这都是我的词槽名字
                        place.Add(item["normalized_word"].ToString());
                        break;

                    case "user_value"://这都是我的词槽名字
                        if(MethodName== "setBright")//这是我的执行函数名,为了防止误读 多写个条件
                            value = Convert.ToInt32( item["normalized_word"]);
                        break;

                    case "user_minutes"://这都是我的词槽名字
                        if(MethodName== "AddCron")//这是我的执行函数名,为了防止误读 多写个条件
                        value = Convert.ToInt32(item["normalized_word"]);
                        break;

                    case "user_color"://这都是我的词槽名字
                        if(MethodName== "setRGB")//这是我的执行函数名,为了防止误读 多写个条件
                            value = Convert.ToInt32(item["normalized_word"]);
                        break;

                    case "user_ct"://这都是我的词槽名字
                        if(MethodName== "setCtAbx")//这是我的执行函数名,为了防止误读 多写个条件
                            value = Convert.ToInt32(item["normalized_word"]);
                        break;
                }
            }

            DeviceType flag; //枚举类型
            foreach(string device in target) //遍历词槽对象
            {
                if (Enum.TryParse(device, true, out flag))//是否存在在枚举中
                {
                    switch (flag) //如果存在在枚举列表中,根据对象的不同找不同的函数
                    {
                        case DeviceType.灯光: //灯光对象
                            {
                                if(place.Count==0) //没有限定空间
                                {
                                    foreach (Yeelight light in DeviceList.YeeLights)
                                        exeFunc(light, MethodName, new ArrayList() { value }); //意图执行函数
                                    break;
                                }

                                Place pFlag;
                                foreach (string placename in place)
                                {
                                    if (Enum.TryParse(placename, true, out pFlag))
                                    {//同样的逻辑,如果有空间限定,将仅操作指定空间的对象。例如 卧室的灯 而非所有灯
                                        foreach (Yeelight light in DeviceList.YeeLights.Where(i => i.Place == pFlag.ToString()))
                                            exeFunc(light, MethodName, new ArrayList() { value });//意图执行函数
                                    }
                                }
                                break;
                            }
                    }
                }
            }
        }

如下是意图执行方法。内部封装了从UNIT取到的执行函数名。同过名称利用C#的reflection类查找对象下的具体的方法地址。

然后将词槽作为方法签名进行执行。为了区分签名的不同。singleSign为单签名方法。有些方法是不需要签名的。可以根据签名的不同分多个类别进行执行。

private static void exeFunc(object target,string MethodName,ArrayList args)
        {
            Type t = target.GetType();//获取对象实体类.
            MethodInfo mt = t.GetMethod(MethodName);//利用字符串查询具体函数地址
            if (mt == null)
            {
                Console.WriteLine("不存在这个函数");
            }
            else
            {
                string str = null;
                string[] singleSign = new string[] { "setBright","setRGB", "setCtAbx","AddCron" };//单参数签名的所有方法集合
                if (singleSign.Contains(MethodName))
                {//单参数方法,将args[0]作为参数执行方法,并获取方法返回值
                    str = (string)mt.Invoke(target, new object[] { args[0] });
                }
                else
                {//无参方法,直接执行获取方法返回值
                    str = (string)mt.Invoke(target, null);
                }
            }
        }
    }
0
TOP
切换版块