赞
踩
最近讯飞的星火大模型更新了2.0版本,增强了AI的语言生成能力。毕竟是国产大语言模型,我也尝试使用了一下星火大模型的应用广场,体验还是很不错的。应用广场提供了很多AI助手工具,也支持用户创建自己的AI助手,能力不局限于自然语言生成,也有一些图片生成工具、视频生成工具之类的,总的来说,还是很有意思的。
同时,星火大模型也提供有api服务,可以很方便的集成到自己的应用里。申请api应用的门槛也比较低,简单填写一些信息,就可以申请试用。试用审核大概半个多小时就结束了,官方提供的免费token数量还是比较可观。针对星火大模型V1.5版本以及V2.0版本,各提供了200万的token试用,非常的良心。我的AI二次元小姐姐项目里,使用chatgpt以及一些开源模型的方式,相对来说还是有一定使用门槛,而接入星火大模型门槛就很低了。
本文就简单介绍一下unity端集成星火大模型API的代码实现,让星火大模型驱动我们的AI二次元小姐姐,与大家聊天吧。
本节内容将简单介绍一下如何在讯飞星火大模型官网,申请试用星火大模型,并创建星火大模型的应用。
星火大模型官方地址:讯飞星火认知大模型-AI大语言模型-星火大模型-科大讯飞 (xfyun.cn)
在申请星火大模型服务之前,需要先注册讯飞的账户,使用手机号码验证就可以了,这里不多赘述。在星火大模型官方站点主页,找到【API测试】按钮,可以点击进入API试用申请的页面。
点击【API测试申请】,即可进入API测试申请界面,如图所示:
在API申请界面中,填写必填的信息。这里需要注意一下,申请API测试,需要创建一个讯飞的应用,我们可以填写一个自己实现申请号的应用ID,也可以在申请页面点击创建一个新的应用,创建应用成功之后,我们就能够获得应用的密钥,这个在后面的接口对接会使用的到。
申请提交之后,耐心等待官方审核即可。时间不会太久,我大概是半小时左右,就完成审批,拿到api的试用服务了。
星火大模型应用申请完成之后,我们就可以拿到应用的密钥。进入到讯飞开放平台的控制台界面,选择到新创建的星火大模型服务,我们就可以看到服务剩余的token数,以及应用的密钥信息了。这个页面可以切换查看V1.5和V2.0两个版本的token使用情况。
星火大模型的接口对接,考虑到跨平台的兼容性,这里选择采用web方式对接,根据官方文档的说明,我们首先需要调用鉴权接口,获取到接口授权,然后在使用websocket协议与服务端握手,websocket握手成功后,需要在60秒内发送请求。接口采用的是流式输出模式,需要对根据返回的数据判断,并拼接成完整的回复信息,大致流程如下如所示:
接下来,将描述一下具体的代码实现。
根据官方文档的说明,开发者需要自行先在控制台创建应用,利用应用中提供的appid,APIKey, APISecret进行鉴权,生成最终请求的鉴权url,鉴权参数如下:
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
host | string | 是 | 请求的主机 | aichat.xf-yun.com(使用时需替换为实际使用的接口地址) |
date | string | 是 | 当前时间戳,采用RFC1123格式,时间偏差需控制在300s内 | Fri, 05 May 2023 10:43:39 GMT |
authorization | string | 是 | base64编码的签名信息 | 参考下方生成方式 |
以下是在unity端实现鉴权url的处理代码:
- /// <summary>
- /// 获取鉴权url
- /// </summary>
- /// <returns></returns>
- private string GetAuthUrl()
- {
- string date = DateTime.UtcNow.ToString("r");
-
- Uri uri = new Uri(url);
- StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
- Append("date: ").Append(date).Append("\n").//
- Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");
-
- string sha = HMACsha256(m_XunfeiSettings.m_APISecret, builder.ToString());
- string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", m_XunfeiSettings.m_APIKey, "hmac-sha256", "host date request-line", sha);
-
- string NewUrl = "https://" + uri.Host + uri.LocalPath;
-
- string path1 = "authorization" + "=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authorization));
- date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
- string path2 = "date" + "=" + date;
- string path3 = "host" + "=" + uri.Host;
-
- NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
- return NewUrl;
- }
-
- public string HMACsha256(string apiSecretIsKey, string buider)
- {
- byte[] bytes = System.Text.Encoding.UTF8.GetBytes(apiSecretIsKey);
- System.Security.Cryptography.HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
- byte[] date = System.Text.Encoding.UTF8.GetBytes(buider);
- date = hMACSHA256.ComputeHash(date);
- hMACSHA256.Clear();
-
- return Convert.ToBase64String(date);
-
- }
根据官方文档说明,星火大模型的1.5版本以及2.0版本的计费模型以及资源地址是不同的,当然我们免费申请的服务是不需要额外付费的,但超过额度了的话,就需要付费了,token的价格如下所示:
服务引擎 | 单价 |
---|---|
讯飞星火认知大模型V1.5 | 0.18元/万tokens |
讯飞星火认知大模型V2.0 | 0.36元/万tokens |
两个版本的api地址分别是:
①星火大模型1.5版本请求地址,对应的domain参数为general
ws(s)://spark-api.xf-yun.com/v1.1/chat
②星火大模型1.5版本请求地址,对应的domain参数为generalv2:
ws(s)://spark-api.xf-yun.com/v2.1/chat
星火大模型的API服务对接部分,按照文档说明,使用websocket协议握手成功之后,就可以根据报文格式发送信息了。请求参数参数部分的接口说明如下:
header部分
参数名称 | 类型 | 必传 | 参数要求 | 参数说明 |
---|---|---|---|---|
app_id | string | 是 | 应用appid,从开放平台控制台创建的应用中获取 | |
uid | string | 否 | 最大长度32 | 每个用户的id,用于区分不同用户 |
parameter.chat部分
参数名称 | 类型 | 必传 | 参数要求 | 参数说明 |
---|---|---|---|---|
domain | string | 是 | 取值为[general,generalv2] | 指定访问的领域,general指向V1.5版本 generalv2指向V2版本。注意:不同的取值对应的url也不一样! |
temperature | float | 否 | 取值为[0,1],默认为0.5 | 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高 |
max_tokens | int | 否 | 取值为[1,4096],默认为2048 | 模型回答的tokens的最大长度 |
top_k | int | 否 | 取值为[1,6],默认为4 | 从k个候选中随机选择⼀个(⾮等概率) |
chat_id | string | 否 | 需要保障用户下的唯一性 | 用于关联用户会话 |
payload.message.text部分
注:text下所有content累计内容 tokens需要控制在8192内
参数名称 | 类型 | 必传 | 参数要求 | 参数说明 |
---|---|---|---|---|
role | string | 是 | 取值为[user,assistant] | user表示是用户的问题,assistant表示AI的回复 |
content | string | 是 | 所有content的累计tokens需控制8192以内 | 用户和AI的对话内容 |
报文示例:
- {
- "header": {
- "app_id": "12345",
- "uid": "12345"
- },
- "parameter": {
- "chat": {
- "domain": "general",
- "temperature": 0.5,
- "max_tokens": 1024,
- }
- },
- "payload": {
- "message": {
- # 如果想获取结合上下文的回答,需要开发者每次将历史问答信息一起传给服务端,如下示例
- # 注意:text里面的所有content内容加一起的tokens需要控制在8192以内,开发者如有较长对话需求,需要适当裁剪历史信息
- "text": [
- {"role": "user", "content": "你是谁"} # 用户的历史问题
- {"role": "assistant", "content": "....."} # AI的历史回答结果
- # ....... 省略的历史对话
- {"role": "user", "content": "你会做什么"} # 最新的一条问题,如无需上下文,可只传最新一条问题
- ]
- }
- }
- }
接口服务将采用流式输出方式,返回回复信息,我们需要解析返回的报文信息,拼接成完整的回复信息。接口响应的报文结构如下所示:
header部分
字段名 | 类型 | 字段说明 |
---|---|---|
code | int | 错误码,0表示正常,非0表示出错;详细释义可在接口说明文档最后的错误码说明了解 |
message | string | 会话是否成功的描述信息 |
sid | string | 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段 |
status | int | 会话状态,取值为[0,1,2];0代表首次结果;1代表中间结果;2代表最后一个结果 |
payload.choices部分
字段名 | 类型 | 字段说明 |
---|---|---|
status | int | 文本响应状态,取值为[0,1,2]; 0代表首个文本结果;1代表中间文本结果;2代表最后一个文本结果 |
seq | int | 返回的数据序号,取值为[0,9999999] |
content | string | AI的回答内容 |
role | string | 角色标识,固定为assistant,标识角色为AI |
index | int | 结果序号,取值为[0,10]; 当前为保留字段,开发者可忽略 |
payload.usage部分(在最后一次结果返回)
字段名 | 类型 | 字段说明 |
---|---|---|
question_tokens | int | 保留字段,可忽略 |
prompt_tokens | int | 包含历史问题的总tokens大小 |
completion_tokens | int | 回答的tokens大小 |
total_tokens | int | prompt_tokens和completion_tokens的和,也是本次交互计费的tokens大小 |
接口响应报文结构示例:
- # 接口为流式返回,此示例为最后一次返回结果,开发者需要将接口多次返回的结果进行拼接展示
- {
- "header":{
- "code":0,
- "message":"Success",
- "sid":"cht000cb087@dx18793cd421fb894542",
- "status":2
- },
- "payload":{
- "choices":{
- "status":2,
- "seq":0,
- "text":[
- {
- "content":"我可以帮助你的吗?",
- "role":"assistant",
- "index":0
- }
- ]
- },
- "usage":{
- "text":{
- "question_tokens":4,
- "prompt_tokens":5,
- "completion_tokens":9,
- "total_tokens":14
- }
- }
- }
- }
使用websocket协议与服务端握手成功后,按照报文格式要求发送信息,等待接口响应,并解析响应数据拼接成完整的回复信息。代码示例如下所示:
- #region websocket连接
- /// <summary>
- /// websocket
- /// </summary>
- private ClientWebSocket m_WebSocket;
- private CancellationToken m_CancellationToken;
- /// <summary>
- /// 连接服务器,获取回复
- /// </summary>
- private async void ConnectHost(string text,Action<string> _callback)
- {
- try
- {
- stopwatch.Restart();
-
- m_WebSocket = new ClientWebSocket();
- m_CancellationToken = new CancellationToken();
- string authUrl = GetAuthUrl();
- string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
-
- //Uri uri = new Uri(GetUrl());
- Uri uri = new Uri(url);
- await m_WebSocket.ConnectAsync(uri, m_CancellationToken);
-
- //发送json
- string _jsonData = text;
- await m_WebSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(_jsonData)), WebSocketMessageType.Binary, true, m_CancellationToken); //发送数据
- StringBuilder sb = new StringBuilder();
- //用于拼接返回的答复
- string _callBackMessage = "";
-
- //播放队列.Clear();
- while (m_WebSocket.State == WebSocketState.Open)
- {
- var result = new byte[4096];
- await m_WebSocket.ReceiveAsync(new ArraySegment<byte>(result), m_CancellationToken);//接受数据
- List<byte> list = new List<byte>(result); while (list[list.Count - 1] == 0x00) list.RemoveAt(list.Count - 1);//去除空字节
- var str = Encoding.UTF8.GetString(list.ToArray());
- sb.Append(str);
- if (str.EndsWith("}"))
- {
- //获取返回的数据
- ResponseData _responseData = JsonUtility.FromJson<ResponseData>(sb.ToString());
- sb.Clear();
-
- if (_responseData.header.code != 0)
- {
- //返回错误
- //PrintErrorLog(_responseData.code);
- Debug.Log("错误码:" + _responseData.header.code);
- m_WebSocket.Abort();
- break;
- }
- //没有回复数据
- if (_responseData.payload.choices.text.Count == 0)
- {
- Debug.LogError("没有获取到回复的信息!");
- m_WebSocket.Abort();
- break;
- }
- //拼接回复的数据
- _callBackMessage += _responseData.payload.choices.text[0].content;
-
- if (_responseData.payload.choices.status == 2)
- {
- stopwatch.Stop();
- Debug.Log("ChatSpark耗时:" + stopwatch.Elapsed.TotalSeconds);
-
- //添加记录
- m_DataList.Add(new SendData("assistant", _callBackMessage));
-
- //回调
- _callback(_callBackMessage);
- m_WebSocket.Abort();
- break;
- }
- }
- }
-
- }
- catch (Exception ex)
- {
- Debug.LogError("报错信息: " + ex.Message);
- m_WebSocket.Dispose();
- }
- }
-
- #endregion
这次的文章简单介绍了讯飞星火大模型的web api的对接流程,并针对接口对接的流程进行了介绍,包括接口的鉴权、websocket握手以及发送报文、响应报文的结构说明,并提供了针对全流程在unity端的实现代码示例。通过上述的代码实现,我们就可以在unity引擎中,使用星火大模型的api来驱动AI二次元小姐姐的对话交互。
上述代码只包含了核心的代码实现,完整的代码工程可以从我的开源项目下载使用,项目包含了针对多种GPT应用的集成工具,以及语音服务的集成,对我这个项目感兴趣的朋友,可以上我的B站号查看,我也做有详细的教程,相关源码可以在的哔哩哔哩主站找到相关视频,在视频介绍以及评论区获取。
国产星火大模型驱动AI小姐姐聊天,unity开源工具包,手把手打造自己的二次元老婆~
上述项目地址传送门:
AI二次元老婆开源项目(unity-AI-Chat-Toolkit):
Github地址:https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit
Gitee地址:https://gitee.com/DammonSpace/unity-ai-chat-toolkit
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。