Unity接入讯飞的大数据模型

原:基于C#+WPF编写的调用讯飞星火大模型工具_c#xf$xccx-CSDN博客

记录一下以防以后用到。

using Newtonsoft.Json;
using System.Collections.Generic;

public class JsonResponse
{
    [JsonProperty("header")]
    public ResponseHeader Header { get; set; }
    [JsonProperty("payload")]
    public ResponsePayload Payload { get; set; }
}
public class ResponseHeader
{
    /// <summary>
    /// 错误码,0表示正常,非0表示出错;详细释义可在接口说明文档最后的错误码说明了解
    /// </summary>
    [JsonProperty("code")]
    public int Code { get; set; }
    /// <summary>
    /// 会话是否成功的描述信息
    /// </summary>
    [JsonProperty("message")]
    public string Message { get; set; }
    /// <summary>
    /// 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段
    /// </summary>
    [JsonProperty("sid")]
    public string Sid { get; set; }
    /// <summary>
    /// 会话状态,取值为[0,1,2];0代表首次结果;1代表中间结果;2代表最后一个结果
    /// </summary>
    [JsonProperty("status")]
    public int Status { get; set; }
}
public class ResponsePayload
{
    [JsonProperty("choices")]
    public ResponseChoices Choices { get; set; }
    [JsonProperty("useage")]
    public ResponseUsage Usage { get; set; }
}
public class ResponseChoices
{
    /// <summary>
    /// 文本响应状态,取值为[0,1,2]; 0代表首个文本结果;1代表中间文本结果;2代表最后一个文本结果
    /// </summary>
    [JsonProperty("status")]
    public int Status { get; set; }
    /// <summary>
    /// 返回的数据序号,取值为[0,9999999]
    /// </summary>
    [JsonProperty("seq")]
    public int Seq { get; set; }
    [JsonProperty("text")]
    public List<ReponseContent> Text { get; set; }
}
public class ReponseContent
{
    /// <summary>
    /// AI的回答内容
    /// </summary>
    [JsonProperty("content")]
    public string Content { get; set; }
    /// <summary>
    /// 角色标识,固定为assistant,标识角色为AI
    /// </summary>
    [JsonProperty("role")]
    public string Role { get; set; }
    /// <summary>
    /// 结果序号,取值为[0,10]; 当前为保留字段,开发者可忽略
    /// </summary>
    [JsonProperty("index")]
    public int Index { get; set; }
}
public class ResponseUsage
{
    [JsonProperty("text")]
    public ResponseUsageDetails Text { get; set; }
}
public class ResponseUsageDetails
{
    /// <summary>
    /// 保留字段,可忽略
    /// </summary>
    [JsonProperty("question_tokens")]
    public int QuestionTokens { get; set; }
    /// <summary>
    /// 包含历史问题的总tokens大小
    /// </summary>
    [JsonProperty("prompt_tokens")]
    public int PromptTokens { get; set; }
    /// <summary>
    /// 回答的tokens大小
    /// </summary>
    [JsonProperty("completion_tokens")]
    public int CompletionTokens { get; set; }
    /// <summary>
    /// prompt_tokens和completion_tokens的和,也是本次交互计费的tokens大小
    /// </summary>
    [JsonProperty("total_tokens")]
    public int TotalTokens { get; set; }
}

 

//构造请求体
using Newtonsoft.Json;
using System.Collections.Generic;

public class JsonRequest
{
    [JsonProperty("header")]
    public RequestHeader Header { get; set; }
    [JsonProperty("parameter")]
    public RequestParameter Parameter { get; set; }
    [JsonProperty("payload")]
    public RequestPayload Payload { get; set; }
}

public class RequestHeader
{
    /// <summary>
    /// 应用appid,从开放平台控制台创建的应用中获取
    /// </summary>
    [JsonProperty("app_id")]
    public string app_id { get; set; }
    /// <summary>
    /// 每个用户的id,用于区分不同用户
    /// </summary>
    [JsonProperty("uid")]
    public string uid { get; set; }
}

public class RequestParameter
{
    [JsonProperty("chat")]
    public RequestChat Chat { get; set; }
}

public class RequestChat
{
    /// <summary>
    /// 指定访问的领域,general指向V1.5版本,generalv2指向V2版本,generalv3指向V3版本 。注意:不同的取值对应的url也不一样!
    /// </summary>
    [JsonProperty("domain")]
    public string domain { get; set; }
    /// <summary>
    /// 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高
    /// </summary>
    [JsonProperty("temperature")]
    public double temperature { get; set; }
    /// <summary>
    /// 模型回答的tokens的最大长度
    /// </summary>
    [JsonProperty("max_tokens")]
    public int max_tokens { get; set; }
}

public class RequestPayload
{
    [JsonProperty("message")]
    public RequestMessage Message { get; set; }
}

public class RequestMessage
{
    [JsonProperty("text")]
    public List<ReuqestContent> Text { get; set; }
}

public class ReuqestContent
{
    /// <summary>
    /// user表示是用户的问题,assistant表示AI的回复
    /// </summary>
    [JsonProperty("role")]
    public string role { get; set; }
    /// <summary>
    /// 用户和AI的对话内容
    /// </summary>
    [JsonProperty("content")]
    public string content { get; set; }
}

 

using System.Collections.Generic;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System;
using System.Linq;

namespace XFYun.SparkChat.SDK
{
    public class SparkWebSDK
    {
        private string _appId;
        private string _apiSecret;
        private string _apiKey;
        private SparkVersions _version;
        private ClientWebSocket _webSocketClient;
        public SparkWebSDK()
        {

        }
        public void Setup(string appId, string apiSecret, string apiKey, SparkVersions version = SparkVersions.V3_5)
        {
            this._apiKey = apiKey;
            this._apiSecret = apiSecret;
            this._appId = appId;
            this._version = version;
        }
        private string GetAuthUrl(string baseUrl, string apiSecret, string apiKey)
        {
            string date = DateTime.UtcNow.ToString("r");
            Uri uri = new Uri(baseUrl);
            var str = $"host: {uri.Host}\ndate: {date}\nGET {uri.LocalPath} HTTP/1.1";

            //使用apisecret,HMACSHA256算法加密str
            var sha256Bytes = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)).ComputeHash(Encoding.UTF8.GetBytes(str));
            var sha256Str = Convert.ToBase64String(sha256Bytes);
            var authorization = $"api_key=\"{apiKey}\",algorithm=\"hmac-sha256\",headers=\"host date request-line\",signature=\"{sha256Str}\"";

            //date要做url处理
            date = Uri.EscapeDataString(date);
            string newUrl = $"ws://{uri.Host}{uri.LocalPath}?authorization={Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization))}&date={date}&host={uri.Host}";
            return newUrl;
        }
        /// <summary>
        /// 询问问题,流式调用response
        /// 返回结果表示调用成功还是失败,如果调用失败,则返回失败原因
        /// </summary>
        /// <param name="question"></param>
        /// <param name="response"></param>
        /// <returns></returns>
        public async Task<(bool, string)> Ask(List<string> questions, CancellationToken token, Action<List<string>> responseHandler)
        {
            try
            {
                string url = "";
                string domain = "";
                switch (this._version)
                {
                    case SparkVersions.V1_5:
                        url = "ws://spark-api.xf-yun.com/v1.1/chat";
                        domain = "general";
                        break;
                    case SparkVersions.V2_0:
                        url = "ws://spark-api.xf-yun.com/v2.1/chat";
                        domain = "generalv2";
                        break;
                    case SparkVersions.V3_0:
                        url = "ws://spark-api.xf-yun.com/v3.1/chat";
                        domain = "generalv3";
                        break;
                    case SparkVersions.V3_5:
                        url = "ws://spark-api.xf-yun.com/v3.5/chat";
                        domain = "generalv3.5";
                        break;
                }
                var newUrl = GetAuthUrl(url, this._apiSecret, this._apiKey);
                this._webSocketClient = new ClientWebSocket();
                await this._webSocketClient.ConnectAsync(new Uri(newUrl), token);

                var request = new JsonRequest()
                {
                    Header = new RequestHeader()
                    {
                        app_id = this._appId,
                        uid = "123"
                    },
                    Parameter = new RequestParameter()
                    {
                        Chat = new RequestChat()
                        {
                            domain = domain,
                            temperature = 0.5,
                            max_tokens = 1024,
                        }
                    },
                    Payload = new RequestPayload()
                    {
                        Message = new RequestMessage()
                        {
                            Text = questions.Select(x => new ReuqestContent()
                            {
                                role = "user",
                                content = x
                            }).ToList()
                        }
                    }
                };
                var jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(request);

                await this._webSocketClient.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(jsonStr)), WebSocketMessageType.Text, true, token);

                var recvBuffer = new byte[1024];

                while (true)
                {
                    WebSocketReceiveResult result = await this._webSocketClient.ReceiveAsync(new ArraySegment<byte>(recvBuffer), token);
                    if (result.CloseStatus.HasValue) return (true, "");
                    if (result.MessageType == WebSocketMessageType.Text)
                    {
                        string recvMsg = Encoding.UTF8.GetString(recvBuffer, 0, result.Count);
                        var response = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonResponse>(recvMsg);
                        if (response.Header.Code != 0)
                        {
                            return (false, response.Header.Message);
                        }

                        if (response.Payload.Choices.Status == 2)//最后一个消息
                        {
                            responseHandler?.Invoke(response.Payload.Choices.Text.Select(x => x.Content).ToList());
                            return (true, "调用成功!");
                        }

                        responseHandler?.Invoke(response.Payload.Choices.Text.Select(x => x.Content).ToList());
                    }
                    else if (result.MessageType == WebSocketMessageType.Close)
                    {
                        return (false, result.CloseStatusDescription);
                    }
                }
            }
            catch (Exception e)
            {
                return (false, e.Message);
            }
            finally
            {
                await this._webSocketClient?.CloseAsync(WebSocketCloseStatus.NormalClosure, "client raise close request", token);
            }
        }
        public async void Close()
        {
            if (_webSocketClient != null)
            {
                await _webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "正常关闭", new CancellationToken());
            }
        }
    }
    public enum SparkVersions
    {
        V1_5,
        V2_0,
        V3_0,
        V3_5
    }


}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using XFYun.SparkChat.SDK;

public class XFTest : MonoBehaviour
{
    private SparkWebSDK sdk;
    public string app_id;
    public string api_secret;
    public string api_key;
    public SparkVersions api_version;

    public InputField request;

    public Text response;

    public Button send;
    // Start is called before the first frame update
    void Start()
    {
        sdk = new SparkWebSDK();
        sdk.Setup(app_id, api_secret, api_key, api_version);
        send.onClick.RemoveAllListeners();
        send.onClick.AddListener(async delegate
        {
            response.text = "";
            var (ok, errMsg) = await sdk.Ask(new List<string>() { request.text }, new System.Threading.CancellationToken(), strs =>
            {
                foreach (var str in strs)
                {
                    response.text += str;
                }
            });
            response.text += "\n我的回答结束!";
            if (!ok)
            {
                Debug.LogError($"error msg = {errMsg}");
            }
        });
    }
}

1. 下载语音SDK并导入到Unity项目中。 2. 在Unity中创建一个空物体并命名为"IFlySpeechRecognizer",然后将IFlySpeechRecognizer.cs脚本文件拖拽到该物体上。 3. 在开放平台上注册账号并创建应用,并获取AppID和API Key等参数。 4. 在IFlySpeechRecognizer.cs脚本中填入AppID和API Key等参数。 5. 编写代码调用语音SDK的API,进行语音识别等操作。 例如,以下代码可以启动语音识别: ```csharp using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class MyRecognizer : MonoBehaviour { private IFlySpeechRecognizer recognizer; private bool isRecording = false; void Start () { recognizer = IFlySpeechRecognizer.createRecognizer (); recognizer.setParameter (IFlySpeechConstant.PARAMS, null); recognizer.setParameter (IFlySpeechConstant.ENGINE_TYPE, IFlySpeechConstant.TYPE_CLOUD); recognizer.setParameter (IFlySpeechConstant.RESULT_TYPE, "json"); recognizer.setParameter (IFlySpeechConstant.LANGUAGE, "zh_cn"); recognizer.setParameter (IFlySpeechConstant.ACCENT, "mandarin"); recognizer.setParameter (IFlySpeechConstant.VAD_BOS, "4000"); recognizer.setParameter (IFlySpeechConstant.VAD_EOS, "1000"); recognizer.setParameter (IFlySpeechConstant.ASR_PTT, "0"); } void Update () { if (Input.GetKeyDown (KeyCode.Space)) { if (!isRecording) { recognizer.startListening (new MyRecognizerListener ()); isRecording = true; } else { recognizer.stopListening (); isRecording = false; } } } private class MyRecognizerListener : IFlyRecognizerListener { public void onVolumeChanged (int volume) { Debug.Log ("Volume: " + volume); } public void onBeginOfSpeech () { Debug.Log ("Speech started."); } public void onEndOfSpeech () { Debug.Log ("Speech ended."); } public void onResult (RecognizerResult result, bool isLast) { Debug.Log ("Result: " + result.getResultString ()); } public void onError (IFlySpeechError error) { Debug.Log ("Error: " + error.getErrorDescription ()); } public void onEvent (int eventType, int arg1, int arg2, string msg) { Debug.Log ("Event: " + msg); } } } ``` 在该代码中,按下空格键可以启动或停止语音识别,语音识别结果将在控制台中输出。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值