[Unity+智谱AI开放平台]调用ChatGLM Tuobo模型驱动AI小姐姐数字人

news2024/11/19 9:31:13

1.简述

        本篇文章主要介绍一下,在Unity端,集成智谱AI开放平台提供的chatglm模型api,实现AI聊天互动相关的功能。从智谱AI官方站点上看到,提供有chatglm turbo的公共模型服务,能够实现32K超长上下文,应用到我们的AI二次元小姐姐项目中,完全足够了。

        价格方面,官方页面上有看到,0.005元/千tokens这样的价格,而且目前新注册用户可以获取18元的API试用金额,核算下来,可以免费使用几百万的token,算是一笔不错的免费额度了。那么接下来,咱们来看一下如何在智谱AI开放平台申请API应用,并集成到Unity中吧。

2.智谱AI开放平台

        首先,进入到智谱AI开放平台的官方站点,通过以下链接,进入到智谱AI开放平台网站

https://maas.aminer.cn/pricingicon-default.png?t=N7T8https://maas.aminer.cn/pricing       

        进入官方站点后,自行注册账号,登录进入到智谱开放平台的控制台界面。

        在控制台界面,可以看到平台赠送的18元试用金。点击查看api key按钮即可进入到应用创建页面,新增一个apikey,后续在Unity端调用api服务时,需要用到这个apikey。

3.接口说明

       3.1 接口对接流程

        根据官方文档说明,可以了解到,目前智谱AI开放平台针对Python以及Java提供有SDK,可以自行下载sdk示例。那么我们使用Unity就没有sdk可用了,只能根据官方文档的说明自行实现相关功能。

        官方介绍了http调用的方式,总体流程上:

        ①接口鉴权,需要根据标准JWT的规则,生成token

        在调用模型接口时需要传鉴权 token 进行认证;当前平台鉴权 token 由用户端生成,鉴权 token 生成采用标准 JWT 中提供的创建方法生成(详细参考:JSON Web Token Introduction - jwt.io)。

        ②api调用,采用post访问资源地址即可。

        这里需要说明一下,POST访问的Url地址,chatglm turbo的模型访问地址:
https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_turbo/sse-invokeicon-default.png?t=N7T8https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_turbo/invoke     

  注:这里我使用的是官方不推进的同步方式,因为项目当前的情况,所以选择了这个方式,官方还提供有异步方式以及SSE两种方式,可以自行阅读文档。

        官方文档地址:
https://maas.aminer.cn/dev/api#chatglm_turboicon-default.png?t=N7T8https://maas.aminer.cn/dev/api#chatglm_turbo

3.2 Unity中的代码实现

        本节内容将介绍在Unity中如何完成接口鉴权以及api的http访问的代码实现。

        一、接口鉴权

        官方文档在接口鉴权流程中的token生成规则的描述不是很清晰,只描述了header和payload的格式,其实还有一部分Signature的生成规则,并没有在文档里说明,详细可以参见JWT的生成规则。

        1、header的内容规则

        根据官方文档,header部分的值为:

 {"alg":"HS256","sign_type":"SIGN"}

  • alg : 属性表示签名使用的算法,默认为 HMAC SHA256(写为HS256)

  • sign_type : 属性表示令牌的类型,JWT 令牌统一写为 SIGN 。

        2、payload 的内容规则

        官方示例为

 {"api_key":{ApiKey.id},"exp":1682503829130, "timestamp":1682503820130}

  • api_key : 属性表示用户标识 id,即用户API Key的{id}部分
  • exp : 属性表示生成的JWT的过期时间,客户端控制,单位为毫秒
  • timestamp : 属性表示当前时间戳,单位为毫秒

        这里需要注意一点,apikey的部分,前面从站点上创建的api key,观察api key的结构,是这样的规则{id}.{secret key},我们拿到apikey时,需要将密钥拆分成两部分,一部分就是上面这个payload需要使用的api_key,而另一部分的secret key,我们在后面生成Signature的时候要用到。

        关于时间戳,生成13位时间戳编码即可。

        鉴权token生成部分的代码如下:

    #region 生成api鉴权token

    /// <summary>
    /// 生成api鉴权 token
    /// </summary>
    /// <returns></returns>
    private string GetToken()
    {
        long expirationMilliseconds = DateTimeOffset.Now.AddHours(1).ToUnixTimeMilliseconds();
        long timestampMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
        string jwtToken = GenerateJwtToken(m_ApiKey, expirationMilliseconds, timestampMilliseconds);
        return jwtToken;
    }
    //获取token
    private string GenerateJwtToken(string apiKeyId, long expirationMilliseconds, long timestampMilliseconds)
    {
        // 构建Header
        string _headerJson = "{\"alg\":\"HS256\",\"sign_type\":\"SIGN\"}";

        string encodedHeader = Base64UrlEncode(_headerJson);

        // 构建Payload
        string _playLoadJson = string.Format("{{\"api_key\":\"{0}\",\"exp\":{1}, \"timestamp\":{2}}}", apiKeyId, expirationMilliseconds, timestampMilliseconds);

        string encodedPayload = Base64UrlEncode(_playLoadJson);

        // 构建签名
        string signature = HMACsha256(m_SecretKey, $"{encodedHeader}.{encodedPayload}");
        // 组合Header、Payload和Signature生成JWT令牌
        string jwtToken = $"{encodedHeader}.{encodedPayload}.{signature}";

        return jwtToken;
    }
    // Base64 URL编码
    private string Base64UrlEncode(string input)
    {
        byte[] inputBytes = Encoding.UTF8.GetBytes(input);
        string base64 = Convert.ToBase64String(inputBytes);
        return base64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
    }
    // 使用HMAC SHA256生成签名
    private string HMACsha256(string apiSecretIsKey, string buider)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(apiSecretIsKey);
        HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
        byte[] date = Encoding.UTF8.GetBytes(buider);
        date = hMACSHA256.ComputeHash(date);
        hMACSHA256.Clear();

        return Convert.ToBase64String(date);

    }
    #endregion

        二、Http访问

        获取到接口鉴权token后,通过POST访问api地址,接口地址如下:
https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_turbo/sse-invokeicon-default.png?t=N7T8https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_turbo/invoke     

        关于接口的报文结构,根据官方提供的接口文档说明,这里做一下详细说明。

        请求报文结构:

prompt

list

调用对话模型时,将当前对话信息列表作为提示输入给模型; 按照 {"role": "user", "content": "你好"} 的键值对形式进行传参; 总长度超过模型最长输入限制后会自动截断,需按时间由旧到新排序

role

string

本条信息作者的角色,可选择user 或 assistant
user 指用户角色输入的信息
assistant 指模型返回的信息

content

string

本条信息的具体内容

temperature

float

采样温度,控制输出的随机性,必须为正数
取值范围是:(0.0,1.0],不能等于 0,默认值为 0.95
值越大,会使输出更随机,更具创造性;值越小,输出会更加稳定或确定
建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数

top_p

float

用温度取样的另一种方法,称为核取样
取值范围是:(0.0, 1.0) 开区间,不能等于 0 或 1,默认值为 0.7
模型考虑具有 top_p 概率质量tokens的结果
例如:0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取tokens
建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数

request_id

string

由用户端传参,需保证唯一性;用于区分每次请求的唯一标识,用户端不传时平台会默认生成。

incremental

boolean

SSE接口调用时,用于控制每次返回内容方式是增量还是全量,不提供此参数时默认为增量返回
true 为增量返回
false 为全量返回

return_type

string

用于控制每次返回内容的类型,空或者没有此字段时默认按照json_string返回
json_string 返回标准的 JSON 字符串
text 返回原始的文本内容

ref

object

用于控制请求时的外部信息引用,目前用于控制是否引用外部信息,空或者没有此字段时默认开启搜索,传参格式
{"enable": "true", "search_query": "历史"}

          回复报文结构:

code

int

错误码,详情请查看错误码说明

msg

string

错误信息

success

boolean

请求成功失败标识,true(成功),false(失败)

data

object

request_id

string

用户在客户端请求时提交的任务编号或者平台生成的任务编号

task_id

string

智谱AI开放平台生成的任务订单号,调用请求结果接口时请使用此订单号

task_status

string

处理状态,PROCESSING(处理中),SUCCESS(成功),FAIL(失败)
注:处理中状态需通过查询获取结果

        接口的调用,采用POST方式即可,示例代码如下:

/// <summary>
    /// 发送数据
    /// </summary> 
    /// <param name="_postWord"></param>
    /// <param name="_callback"></param>
    /// <returns></returns>
    public override IEnumerator Request(string _postWord, System.Action<string> _callback)
    {
        stopwatch.Restart();
        string jsonPayload = JsonConvert.SerializeObject(new RequestData
        {
            model=m_Type.ToString(),
            prompt = m_DataList
        });

        using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
        {
            byte[] data = System.Text.Encoding.UTF8.GetBytes(jsonPayload);
            request.uploadHandler = (UploadHandler)new UploadHandlerRaw(data);
            request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();

            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", GetToken());

            yield return request.SendWebRequest();

            if (request.responseCode == 200)
            {
                string _msg = request.downloadHandler.text;
                ResponseData response = JsonConvert.DeserializeObject<ResponseData>(_msg);

                if (response.data.choices.Count > 0)
                {
                    string _msgBack = response.data.choices[0].content;

                    //回调
                    _callback(_msgBack);
                }
                else
                {
                    Debug.Log(_msg);
                }
            }

        }

        stopwatch.Stop();
        Debug.Log("chatGLM Turbo耗时:" + stopwatch.Elapsed.TotalSeconds);
    }



        数据定义:

[Serializable]
    private class RequestData
    {
        [SerializeField] public string model;
        [SerializeField] public List<SendData> prompt;
        [SerializeField] public float temperature = 0.7f;
    }

    [Serializable]
    private class ResponseData
    {
        [SerializeField] public int code;
        [SerializeField] public string msg = string.Empty;
        [SerializeField] public string success = string.Empty;
        [SerializeField] public ReData data=new ReData();

    }

    [Serializable]
    private class ReData
    {
        [SerializeField] public string task_id = string.Empty;
        [SerializeField] public string request_id = string.Empty;
        [SerializeField] public string task_status = string.Empty;
        [SerializeField] public List<SendData> choices=new List<SendData>();
    }

4. Unity端数字人配置

        项目的源码已经发布到Github了,我们可以直接下载,并导入到unity中使用,要求unity版本在2020.3.44及以上。导入工具包之后,可以在Scene文件夹下,找到示例场景,在场景中找到LLM->chatglm Turbo对象,这里就维护了智谱AI开放平台的模型调用脚本。

        项目已经实现了智谱AI开放平台对接所需的接口鉴权以及API访问的代码,我们只需要在控制台中,找到创建好的api key,将密钥填写到脚本中的{Key}参数即可。

        详细配置,可以到我的B站主页,查看本期视频的配置过程。

5.结束语
      

        这次的文章简单介绍了智谱AI开放平台的API的对接流程,并针对接口对接的流程进行了介绍,包括接口的鉴权、基于JWT的token生成规则,以及chatglm turbo模型的接口调用代码示例等内容,通过上述的代码实现,我们就可以在unity引擎中,使用智谱AI开放平台的api来驱动AI二次元小姐姐的对话交互。完整的代码工程可以从我的开源项目下载使用,项目包含了针对多种GPT应用的集成工具,以及语音服务的集成,对我这个项目感兴趣的朋友,可以上我的B站号查看,我也做有详细的教程,相关源码可以在的哔哩哔哩主站找到相关视频,在视频介绍以及评论区获取。

[Unity+AI Chat+智谱AI]轻松实现32K超长上下文对话, 对接智谱AI开放平台ChatGLM Turbo,简单配置AI二次元小姐姐


项目地址传送门:

AI二次元老婆开源项目(unity-AI-Chat-Toolkit):

Github地址:https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit

Gitee地址:https://gitee.com/DammonSpace/unity-ai-chat-toolkit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1155256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 中__name__ == ‘__main__‘使用说明

在学习C语言的时候&#xff0c;程序的运行是从main函数开始的&#xff0c;因此&#xff0c;功能代码一般写到main函数中&#xff0c;子程序如果想要调用&#xff0c;也需要在main函数中进行调用。 然而&#xff0c;Python语言中&#xff0c;程序从第一行就开始执行(定义函数除外…

不同源安装nginx

Nginx是一款高性能的Web服务器软件。在安装Nginx时&#xff0c;可以选择不同的安装源。 1.官方源&#xff1a;在官方网站下载Nginx的源代码&#xff0c;然后进行编译安装。 2.EPEL源&#xff1a;EPEL (Extra Packages for Enterprise Linux)源是针对Red Hat、CentOS、Scienti…

处理SAP资产折旧AFAB 过账报错:“科目 8019010100 要求一个成本会计分配”

会计在进行资产折旧AFAB时 报错如下所示&#xff1a; 原因分析&#xff1a; 折旧时没有把资产设置得成本中心带到过账凭证的成本中心字段中去。而资产中已经维护了成本中心了。 所以要在资产过账的科目分配中设置一下路径如下&#xff1a; 或者TCODE&#xff1a;ACSET科目设置这…

Java集合操作集锦

原文链接 Java集合操作集锦 集合是最为常见的容器&#xff0c;在日常工作之中经常用到&#xff0c;一些集合的常规操作以及不同的集合之间的转换&#xff0c;虽然看似是基础中的基础&#xff0c;但实践中会发现并不是那么显而易见的&#xff0c;特别是涉及boxing的时候&#x…

NFTScan 发展成为 PlatON 网络最大验证者节点之一

关于 PlatON 区块链&#xff1a;PlatON 是一个开放的金融基础设施&#xff0c;其核心是隐私保护计算。在 LatticeX 基金会的发起和推动下&#xff0c;目标是打造 Web3 时代领先的区块链平台。 PlatON 通过底层基础设施、支付清算系统、资产流通管理平台&#xff0c;构建去信任的…

ArcGIS统计各种土地利用类型的总面积

如下图为研究区多个村的土地利用现状图,现在需统计每种类型的面积总和,以及每个行政村内各种土地利用类型的总面积。本文通过案例的形式,讲解ArcGIS中两种常用的分类统计面积的工具,建议收藏。 文章目录 1. 加载土地利用数据2. 常规属性汇总统计3. 汇总统计数据1. 加载土地…

软件测试之BUG篇(定义,创建,等级,生命周期)

目录 1. BUG 的定义 2. 如何创建 BUG 3. BUG 等级 4. BUG 生命周期 高频面试题&#xff1a; 1. BUG 的定义 当且仅当产品规格书存在且正确时&#xff0c;程序的实现和规格书的要求不匹配时&#xff0c;那就是软件错误。当产品规格说明书没有提到的功能时&#xff0c;以用户…

[MySQL]——SQL预编译、动态sql

键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、SQL的预编译 &#x1f4d5;一条SQL语句的执行过程 &#x1f4d5;弊端 &#x1f4d5;预编译SQL的优势 &#x1f4d5;两种参数占位符 &#x1f4d5;小结 二、动态SQL &#x1f4d5;概念介绍&#xff1a; &#x1f4…

协程框架nty_co

一、为什么要有协程&#xff1f; 以DNS请求为例子&#xff0c;客户端向服务器发送域名&#xff0c;服务器回复该域名对应得IP地址。 我们想要以同步的编程方式获得异步的性能&#xff01;&#xff01;&#xff01; 在Linux下&#xff0c;常使用IO多路复用器epoll来管理客户端…

YOLO算法改进4【中阶改进篇】:添加DeformableConvolution卷积模块

论文地址: https://arxiv.org/abs/1811.11168 源码地址:https://github.com/msracver/Deformable-ConvNets 传统的卷积操作是将特征图分成一个个与卷积核大小相同的部分,然后进行卷积操作,每部分在特征图上的位置都是固定的。这样,对于形变比较复杂的物体,使用这种卷积的…

C#学习相关系列之多线程---lock线程锁的用法

一、lock的作用 Lock可以看成在操作系统中的临界区&#xff0c;Lock区域内的代码表示临界区&#xff0c;使得同一时间只有一个线程能够进入Lock所包含的函数中&#xff0c;实现原子操作&#xff0c;保护同一资源只有一个线程进行修改&#xff0c;实现不同线程中数据的同步。 …

【数据结构】数组和字符串(十二):顺序存储字符串的基本操作(串长统计、查找、复制、插入、删除、串拼接)

文章目录 4.3 字符串4.3.1 字符串的定义与存储4.3.2 字符串的基本操作&#xff08;顺序存储&#xff09;1. 串长统计2. 串定位3. 串复制4. 串插入5. 串删除6. 串拼接7.主函数8. 代码整合及优化 4.3 字符串 字符串(String)是由零个或多个字符(char)顺序排列组成的有限序列&#…

基于RFID技术的优化医药供应链管理解决方案

一、社会背景和挑战 随着全球假药问题的严重性日益凸显&#xff0c;医疗产品的追溯和管理变得越来越重要。据世界卫生组织报告&#xff0c;全球假药比例已超过10%&#xff0c;而中国每年至少有20万人死于假药和不当用药。在国际上&#xff0c;医疗产品的追溯体系已成为监管机构…

总线类设备驱动——IIC

目录 一、本章目标 二、IIC设备驱动 2.1 I2C协议简介 2.2 LinuxI2C驱动 2.3 I2C 设备驱动实例 一、本章目标 一条总线可以将多个设备连接在一起&#xff0c;提高了系统的可扩展性能。这个互联的系统通常由三部分组成:总线控制器、物理总线(一组信号线) 和设备。总线控制器…

视频监控平台EasyCVR分组接口出现“pending”报错,该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、视频能力灵活&#xff0c;能对外分发RTMP、RTSP、…

直线导轨的误差匹配度如何?

直线导轨的误差匹配度是评估导轨之间配合精度的重要指标&#xff0c;导轨之间的配合精度越高&#xff0c;误差匹配度就会越好&#xff0c;反之则越差。 在直线导轨的生产和加工过程中&#xff0c;每个导轨都会产生一定误差&#xff0c;例如平行误差、垂直误差、轨面平整度、滑块…

什么是跨域问题?如何解决?

跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。但这个保护机制也带来了新的问题,它的问题是给不同站点之间的正常调用,也带来的阻碍,那怎么解决这个问题呢?接下来…

2023软件测试八股文最新版(含答案+文档)

一、Web 自动化测试 1、Selenium 中 hidden 或者是 display &#xff1d; none 的元素是否可以定位到&#xff1f; 不能&#xff0c;可以写 JavaScript 将标签中的 hidden 先改为 0&#xff0c;再定位元素 2、Selenium 中如何保证操作元素的成功率&#xff1f;也就是说如何保…

连续分析:提高应用效率和成本效益的关键

作者&#xff1a;John Knoepfle 最近&#xff0c;Elastic Universal Profiling 已经正式发布。 它是我们可观察性解决方案的一部分&#xff0c;允许用户在生产环境中进行整个系统的连续分析。 如果你不熟悉连续分析&#xff0c;你可能想知道通用分析是什么以及为什么你应该关心…

【1++的Linux】之信号(一)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;关于信号二&#xff0c;深剖信号的产生1. 键盘组合建产生信号2.核心转储3. 系统调用接口产生信号4. 由软件条件产生信号5. 硬件异常产生信号 一&#xff0c;…