unity-C#调用百度千帆AppBuilder的OpenApi

功能描述

使用百度千帆AppBuilder平台,通过api调用的方式实现AI大模型对话功能(文字)

准备工作

百度智能云账号

请自行在百度智能云进行创建
百度智能云官网
在这里插入图片描述
tips记得开通大模型的服务(需付费)

创建应用

进入AppBuilder点击创建应用
在这里插入图片描述

编辑应用

设置你需要的应用信息,如果有知识库的话需要设置对应的知识库(一个应用目前只能对应一个知识库)

  1. 设置名字和头像-这个只在网页访问的时候会显示
  2. 设置角色设定,可以先输入一些关键词,点击优化让ai帮你优化
  3. 选择知识库一个应用只能对应一个知识库(20240430)
  4. 还可以设置你需要的内容
  5. 右上角设置基模(目前ERNIE-4.0-8K比较贵,ERNIE-3.5-8K相对便宜效果也不错,根据实际需求选择即可)
  6. 右下角输入内容预览效果
  7. 以上内容确定后点击右上角的发布即可
    在这里插入图片描述

创建Api秘钥

在这里插入图片描述
点击右上方的个人中心图标
点击Api秘钥
在这里插入图片描述
新增秘钥,点击复制按钮一键复制秘钥

Api调用流程

官方文档

在这里插入图片描述
调用流程如下:

  1. 获取创建的应用的appid
  2. 获取api秘钥
  3. 先调用新建会话的api,获取conversation_id
  4. 根据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的内容

  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淳杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值