目录
- 功能描述
- 准备工作
- 百度智能云账号
- 创建应用
- 编辑应用
- 创建Api秘钥
- Api调用流程
- unity代码
- Unitywebrequest
- 非流式
- 流式
- 注意事项
- Restsharp
功能描述
使用百度千帆AppBuilder平台,通过api调用的方式实现AI大模型对话功能(文字)
准备工作
百度智能云账号
请自行在百度智能云进行创建
百度智能云官网
tips
记得开通大模型的服务(需付费)
创建应用
进入AppBuilder点击创建应用
编辑应用
设置你需要的应用信息,如果有知识库的话需要设置对应的知识库(一个应用目前只能对应一个知识库)
- 设置名字和头像-这个只在网页访问的时候会显示
- 设置角色设定,可以先输入一些关键词,点击优化让ai帮你优化
- 选择知识库
一个应用只能对应一个知识库(20240430)
- 还可以设置你需要的内容
- 右上角设置基模(目前
ERNIE-4.0-8K
比较贵,ERNIE-3.5-8K相对便宜效果也不错,根据实际需求选择即可) - 右下角输入内容预览效果
- 以上内容确定后点击右上角的发布即可
创建Api秘钥
点击右上方的个人中心图标
点击Api秘钥
新增秘钥,点击复制按钮一键复制秘钥
Api调用流程
官方文档
调用流程如下:
- 获取创建的应用的
appid
- 获取
api秘钥
- 先调用新建会话的api,获取
conversation_id
- 根据
conversation_id
调用大模型对话接口正式发起会话
unity代码
Unitywebrequest
非流式
使用非流式的调用方式的话就跟平常的api调用没差,这里就不多做说明了
流式
const string API_KEY = "api秘钥";
const string _baseUrl = "https://qianfan.baidubce.com/v2/app/conversation";
const string _startConversRoute = "/runs";
const string _appId = "appid";
RequestBody _reqBody;//实例化的请求体
string _temResultTotal = "";
string _temAsk = "";
private StreamReader streamReader;
private MemoryStream responseStream;
private string _temConversationID;//临时对话id
const string TAG = "YiyanAppBuilderApiCtr";
///调用接口
///
IEnumerator YiyanAppBuilderStreamIE(string prompt)
{
this._temAsk = prompt;
yield return GetConversationID();//调用新建会话接口获取conversationid
byte[] bodyRaw = Data2byte(prompt);//将请求的内容封装在请求体中最后一并转化为字节数据
using (UnityWebRequest request = UnityWebRequest.Post($"{_baseUrl}{_startConversRoute}", ""))
{
request.SetRequestHeader("Accept", "application/octet-stream");//改行可加可不加
request.SetRequestHeader("Authorization", $"Bearer {API_KEY}");
request.SetRequestHeader("Content-Type", "application/json");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);//将请求的数据添加如请求中
request.SendWebRequest();//发起调用
byte[] results = new byte[1024];
//try
//{ tips 如果追求流式效果,此处不能使用trycatch包裹业务代码,否则实现的效果和非流式一样
while (!request.isDone)
{
yield return new WaitForSeconds(0.5f);//添加yield return (填null或者0)都行
results = request.downloadHandler.data;
this.HandleStreamData(results);//对接受的数据进行处理
}
if (request.isDone && results != null)
{
//业务逻辑
}
//}
//catch (Exception ex)
//{
//}
}
yield return null;
}
private void HandleStreamData(byte[] results)
{
string line = "";
if (results != null)
{
responseStream = new MemoryStream(results);
streamReader = new StreamReader(responseStream);
while ((line = streamReader.ReadLine()) != null)
{
string _temResult = "";
if (line.Length < 6) continue;
try
{
//将字节流数据的头信息(data: )去掉,然后通过json转换得到我们想要的数据
if (JObject.Parse(line.Substring(5))["answer"].ToString() == "") continue;
Debug.Log(line.Substring(5));
_temResult = JObject.Parse(line.Substring(5))["answer"].ToString();
}
catch (Exception ex)
{
//说明json转换失败,跳过
Debug.Log("yiyan transform byte2json fail>>>>" + ex.Message + line.Substring(5));
continue;
}
if (!_temStreamCBList.ContainsKey(_temResult))
{
//对数据进行过滤,将出现的特殊符号去掉
_temResult = _temResult.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");
_temResult = FilterStr(_temResult);
if (_temResult == null || _temResult == "") continue;
Debug.Log(_temResult);
//将流数据转换加入队列,调用循环进行播放和处理
this._temResultTotal += _temResult;
try
{
_temStreamCBList.Add(_temResult, _temResult);
}
catch (Exception ex)
{
Log.Info($"{TAG}>>>ArgumentException: An item with the same key has already been added. Key");
continue;
}
if (_temStreamCBList.Count == 1)
{
//业务逻辑
}
}
}
}
}
/**
* 根据apikey和appid获取conversation_id用于开启对话
*/
IEnumerator GetConversationID()
{
Dictionary<string, string> form = new Dictionary<string, string>();
form.Add("app_id", _reqBody.app_id);
string _jsonBody = JsonConvert.SerializeObject(form);
byte[] bytes = Encoding.UTF8.GetBytes(_jsonBody);
using (UnityWebRequest request = UnityWebRequest.Post(_baseUrl, ""))
{
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Authorization", $"Bearer {API_KEY}");
request.uploadHandler = new UploadHandlerRaw(bytes);
yield return request.SendWebRequest();
ResponseBody response = JsonUtility.FromJson<ResponseBody>(request.downloadHandler.text);
_temConversationID = response.conversation_id;
Debug.Log(_temConversationID);
}
}
private byte[] Data2byte(string prompt)
{
_reqBody.query = prompt;
_reqBody.conversation_id = _temConversationID;
string body = JsonConvert.SerializeObject(_reqBody);
byte[] bodyRaw = Encoding.UTF8.GetBytes(body);
return bodyRaw;
}
public string FilterStr(string str)
{
string pattern = @"\*|\^|\[(\d+)\]"; // 匹配 *、^、[ 和 ] 字符 以及[]里的数字
//Regex reg = new Regex("\\s+");
string _regResult = Regex.Replace(str, pattern, "");
//Debug.Log(_regResult);
return _regResult;
}
#region 请求yiyan-api需要的请求体
[Serializable]
class RequestBody
{
public string app_id;
public string query;
public bool stream;
public string conversation_id;
}
[Serializable]
class ResponseBody
{
public string request_id;
public string conversation_id;
}
#endregion
注意事项
截止至20240430也就是今天为止
官方请求后返回的数据中会在最后有关于知识库的下标的数据,如下图
官方的回复是
因此在实际进行调用的时候还需要对最后的数据进行过滤
通过以上流程即可调用成功
Restsharp
该插件可以更便捷的实现调用,不过该插件存在多线程(UI更新不及时)的问题,因此不做该插件实现调用api的内容