using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using LitJson;
using UnityEngine;
using UnityEngine.Networking;
using System.Net;
using System.Text;
using System.IO;
using System.Reflection;
using Newtonsoft.Json;
using UnityEngine.Rendering.PostProcessing;
using Debug = UnityEngine.Debug;
public class QueryAIManager : MonoBehaviour
{
#region delegate
///
/// 机器人回复委托
///
///
public delegate void QueryAICallResult(JsonData res);
public event QueryAICallResult QueryCallRes;
public AIChatCallType ChatType;
///
/// 回复用户时的委托
///
///
public delegate void DialogResult(string result);
public event DialogResult DialogCallRes;
///
/// 不满足条件的结果
///
public Action DialogNoSatisfyResoult;
///
/// 语音合成出现问题
///
public Action VoiceError;
///
/// 机器人回复的执行函数
///
///
public delegate void QueryEvent(string enent);
public event QueryEvent DialogResEvent;
public delegate void VoiceSuccess(string timeStemp);
public event VoiceSuccess voiceSuccess;
#endregion
///
/// 设置当前环境,默认是测试版
///
private bool IsRelease = false;
private string API_KEY;
private string SECRET_KEY;
private string APP_ID;
private string GetAccessTokenUrl = "https://aip.baidubce.com/oauth/2.0/token";
private string UnitUrl;
private string SynthesisUrl = "http://tsn.baidu.com/text2audio";//语音合成url
[HideInInspector]
public string accessToken = "";
private JsonData jsonDataSend;
private string logId = "";
public string query = "";
[HideInInspector]
public string userId = string.Empty;
private HttpWebRequest request;
private string sessionId = "";
[HideInInspector]
public Action dialogCallBack;
public string WriteLocalUrl;
public Action AudioIndexCall;
///
/// 存储播放过的音效的字典(时间是key,路径为Vlaue)
///
[HideInInspector]
public Dictionary DicAudio;
[HideInInspector]
public int AudioIndex = 0;
int index = 0;
private string FuncStr = "";
///
/// 是否存在录音设备
///
public bool isHasDevice = false;
///
/// 语音合成的当前时间
///
private string CurAudioTimestemp = "";
#region Sigleton
private static QueryAIManager m_Instance = null;
public static QueryAIManager Singleton
{
get
{
if (m_Instance == null)
m_Instance = CEMain.queryAiMger;
return m_Instance;
}
}
#endregion Singleton
void Awake()
{
API_KEY = "nSHVHmSI6wKof6BRdUke1uKZ";
SECRET_KEY = "6msxcehHFAVdn6UFgzZqy02BAiskj75n";
APP_ID = "15981168";
if (IsRelease)
{
UnitUrl = "https://unit.bj.baidubce.com/rpc/2.0/unit/bot/chat?access_token=";
}
else
{
UnitUrl = "https://aip.baidubce.com/rpc/2.0/unit/bot/chat?access_token=";
}
GetAccessToken();
}
void Start()
{
QueryCallRes += QueryCallBackResult;
AudioIndexCall = GetAudioIndex;
logId = UtilMgr.GUID(12);
WriteLocalUrl = Util.GetRootPath() + "Audio/";
DicAudio = new Dictionary();
DeleteVoiceDir();//每次重新登录,都要删除下载的语音文件,以达到节省硬盘空间的目的
}
///
/// 删除语音文件
///
public void DeleteVoiceDir()
{
if (Directory.Exists(WriteLocalUrl))
{
DicAudio.Clear();
DirectoryInfo direction = new DirectoryInfo(WriteLocalUrl);
FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
if (files[i].Name.EndsWith(".wav"))
{
File.Delete(WriteLocalUrl + files[i].Name);
}
}
}
}
void GetAudioIndex(int index)
{
AudioIndex = index;
}
public void StopCurServiceAudio()
{
CESoundManager.Singleton._StopSound(AudioIndex);
}
///
/// 向客服说话
///
///
public void SayToAIServices(string dialog)
{
string host = UnitUrl + accessToken;
// Debug.Log("access_token:" + host);
JsonData send = new JsonData();
send["version"] = "2.0";
send["bot_id"] = "35577";
send["log_id"] = logId;
send["request"] = new JsonData();
send["request"]["user_id"] = userId;
send["request"]["query"] = dialog;
send["request"]["query_info"] = new JsonData();
send["request"]["query_info"]["type"] = "TEXT";
send["request"]["query_info"]["source"] = "ASR";
//send["request"]["query_info"]["asr_candidates"][0]=;
send["request"]["bernard_level"] = 1;
JsonData bot_session = new JsonData();
bot_session["session_id"] = sessionId;
send["bot_session"] = JsonMapper.ToJson(bot_session);
string sendStr = JsonMapper.ToJson(send);
//Debug.Log("sendstr:" + sendStr);
StartCoroutine(DiaLogPost(host, sendStr, (res) =>
{
if (DialogNoSatisfyResoult != null)
{
DialogNoSatisfyResoult("意图识别出错:" + res);
}
}));
}
///
/// 机器人回复
///
///
public void QueryCallBackResult(JsonData res)
{
//Debug.Log("result:" + res["response"].ToJson());
//return;
if (res["response"]["status"].ToString().ToInt() != 0)
{
if (DialogNoSatisfyResoult != null)
{
DialogNoSatisfyResoult("意图识别出错:" + res["response"]["msg"].ToString());
}
Debug.LogWarning(res["response"]["msg"].ToString());
return;
}
JsonData bot = JsonMapper.ToObject(res["bot_session"].ToString());
sessionId = bot["session_id"].ToString();
foreach (JsonData item in res["response"]["action_list"])
{
/*
* clarify(澄清)
satisfy(满足)
guide(引导到对话意图)
faqguide(引导到问答意图)
understood(理解达成,注:内部使用)
failure(理解失败)
chat(聊天话术)
event(触发事件,在答复型对话回应中选择了"执行函数",将返回event类型的action)
*/
string actionType = item["type"].ToString();
if (actionType.Equals("failure"))//不满足结果条件时,理解失败
{
if (DialogNoSatisfyResoult != null)
{
DialogNoSatisfyResoult(item["say"].ToString());
}
}
else if (actionType.Equals("event"))//满足结果条件时事件
{
if (DialogResEvent != null)
{
DialogResEvent(item["custom_reply"].ToString());
}
}
else if (actionType.Equals("guide") || actionType.Equals("faqguide"))//不满足结果条件时引导其他意图
{
StringBuilder sb = new StringBuilder();
JsonData data = item["refine_detail"];
int index = 0;
foreach (JsonData var in data["option_list"])
{
index++;
sb.AppendFormat("\n{0}.{1}", index, var["option"].ToString());
}
if (DialogNoSatisfyResoult != null)
{
DialogNoSatisfyResoult(item["say"] + sb.ToString());
}
}
else if (actionType.Equals("satisfy"))//满足结果条件理解正确
{
if (DialogCallRes != null)
{
DialogCallRes(item["say"].ToString());
}
}
else if (actionType.Equals("clarify"))//不满足结果条件时澄清
{
if (DialogNoSatisfyResoult != null)
{
DialogNoSatisfyResoult(item["say"].ToString());
}
}
else if (actionType.Equals("chat"))
{
}
}
}
#region 语音合成
///
/// 语音合成
///
///
public void SpeechSynthesis(string txt)
{
Debug.Log("语音合成text:"+ txt);
WWWForm form = new WWWForm();
form.AddField("per", 0);//发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
form.AddField("spd", 6);//语速,取值0-15,默认为5中语速
form.AddField("pit", 5);//音调,取值0-15,默认为5中语调
form.AddField("vol", 15);//音量,取值0-15,默认为5中音量
form.AddField("tex", txt);
MyFamily fi = GameData.Singleton.getMyFamily();
form.AddField("cuid", fi.nFamilyID.ToString());
form.AddField("lan", "zh");
form.AddField("ctp", 1);
form.AddField("tok", accessToken);
form.AddField("aue", 6);
StartCoroutine(RequestSpeech(SynthesisUrl, form));
}
IEnumerator RequestSpeech(string url, WWWForm form)
{
using (UnityWebRequest www = UnityWebRequest.Post(url, form))
{
www.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
yield return www.SendWebRequest();
if (www.isNetworkError)
{
if (VoiceError != null)
{
VoiceError(www.error);
}
yield return www.error;
}
else
{
if (www.responseCode == 200)
{
if (www.GetResponseHeader("Content-Type").ToLower() == "application / json")
{
JsonData resData = JsonMapper.ToObject(www.downloadHandler.text);
if (VoiceError != null)
{
VoiceError(resData["err_msg"].ToString());
}
}
else
{
if (www.isDone)
{
string audioName = UtilMgr.GUID(6);
if (!Directory.Exists(WriteLocalUrl))
{
Directory.CreateDirectory(WriteLocalUrl);
}
if (!File.Exists(WriteLocalUrl + "audio_" + audioName + ".wav"))
{
File.Delete(WriteLocalUrl + "audio_" + audioName + ".wav");
}
File.WriteAllBytes(WriteLocalUrl + "audio_" + audioName + ".wav", www.downloadHandler.data);
CurAudioTimestemp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
if (!DicAudio.ContainsKey(CurAudioTimestemp))
{
DicAudio.Add(CurAudioTimestemp, WriteLocalUrl + "audio_" + audioName + ".wav");
}
if (voiceSuccess != null)
{
voiceSuccess(CurAudioTimestemp);
}
}
}
}
}
}
}
#endregion
#region 对话POST请求
///
/// 对话POST请求
///
///
///
///
///
IEnumerator DiaLogPost(string uri, string postdata, Action error_code)
{
WWWForm form = new WWWForm();
Dictionary header = form.headers;
header["Content-Type"] = "application/json; charset=utf-8";
using (WWW www = new WWW(uri, Encoding.UTF8.GetBytes(postdata), header))
{
yield return www;
if (www.error != null)
{
yield return www.error;
}
else
{
Debug.Log(www.text);
JsonData resData = JsonMapper.ToObject(www.text);
if (error_code != null)
{
double errCode = resData["error_code"].ToString().ToDouble();
if (errCode != 0 && error_code != null)
{
error_code(resData["error_msg"].ToString());
yield break;
}
if (QueryCallRes != null)
{
QueryCallRes(resData["result"]);
}
}
}
}
}
#endregion
#region 获取和刷新AccessToken (最终建议在server端获取)
///
/// 获取accesstoken的POST请求
///
///
///
///
///
private IEnumerator GetTokenPostUrl(string url, WWWForm form, Action getResult)
{
using (UnityWebRequest www = UnityWebRequest.Post(url, form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
yield return www.error;
}
else
{
if (www.isDone)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("回调:{0}", www.downloadHandler.text);
Debug.Log("sb:" + sb);
getResult(www.downloadHandler.text);
}
}
}
}
///
/// 获取token
///
///
///
IEnumerator GetToken(Action getResult)
{
WWWForm form = new WWWForm();
form.AddField("grant_type", "client_credentials");
form.AddField("client_id", API_KEY);
form.AddField("client_secret", SECRET_KEY);
yield return StartCoroutine(GetTokenPostUrl(GetAccessTokenUrl, form, getResult));
}
private bool isGetAccessToken = false;
///
/// 获取Token
///
///
void GetAccessToken()
{
if (isGetAccessToken)
{
return;
}
StartCoroutine(GetToken((str) =>
{
LitJson.JsonData data = LitJson.JsonMapper.ToObject(str);
accessToken = data["access_token"].ToString();
isGetAccessToken = true;
}));
}
#endregion
}