基于C#+WPF编写的调用讯飞星火大模型工具

工具源码:https://github.com/lishuangquan1987/XFYun.SparkChat

工具效果截图:

支持流式输出:

其中ApiKey/ApiSecret/AppId需要自己到讯飞星火大模型官网去注册账号申请,免费的。

申请地址:https://xinghuo.xfyun.cn/

注册之后,在如下的服务管理里面即可看到自己的ApiKey/ApiSecret/AppId

拿到了那三个东西之后填入就可以进行聊天啦。

核心代码C#如下:

csharp 复制代码
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_0)
        {
            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;
                }
                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()
                    {
                        AppId = this._appId,
                        Uid = "123"
                    },
                    Parameter = new RequestParameter()
                    {
                        Chat = new RequestChat()
                        {
                            Domain = domain,
                            Temperature = 0.5,
                            MaxTokens = 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
    }


}
相关推荐
野生技术架构师20 小时前
牛客网Java 高频面试题总结(2025最新版)
java·开发语言·面试
一只鹿鹿鹿20 小时前
系统安全设计方案书(Word)
开发语言·人工智能·web安全·需求分析·软件系统
持梦远方20 小时前
【C++日志库】启程者团队开源:轻量级高性能VoyLog日志库完全指南
开发语言·c++·visual studio
聪明努力的积极向上20 小时前
【C#】HTTP中URL编码方式解析
开发语言·http·c#
嵌入式-老费20 小时前
自己动手写深度学习框架(快速学习python和关联库)
开发语言·python·学习
ctgu9021 小时前
PyQt5(八):ui设置为可以手动随意拉伸功能
开发语言·qt·ui
CVer儿21 小时前
libtorch ITK 部署 nnUNetV2 模型
开发语言
asyxchenchong88821 小时前
OpenLCA、GREET、R语言的生命周期评价方法、模型构建
开发语言·r语言
没有梦想的咸鱼185-1037-166321 小时前
【生命周期评价(LCA)】基于OpenLCA、GREET、R语言的生命周期评价方法、模型构建
开发语言·数据分析·r语言
程序猿20231 天前
Python每日一练---第三天:删除有序数组中的重复项
开发语言·python