C#(WPF)通过WebAPI方式调用科大讯飞实现语音识别

参考连接:

语音听写(流式版)WebAPI 文档 | 讯飞开放平台文档中心 (xfyun.cn)

http://t.csdnimg.cn/4zSMA

http://t.csdnimg.cn/1IXfO

        在用WPF做上位机的时候需要用到科大讯飞的语音识别功能,看了看官方文档在Windows上想要实现语音识别可以通过WebAPI或者SDK的方式实现。

        在网上对比了两种方法,SDK好像不能直接用到C#上面,而且还要往文件里引入好几个库,本着偷懒的想法就选择了WebAPI的方法,相对来说会简洁一点。

        使用的是.NET Framework 4.7.2

        如果将修改成以下参数,识别速度会大大加快但是没有经过大量测试不能保证稳定性。

        int frameSize = 6400;
        int intervel = 10;

3.14更新:

        主要是在接收返回结果的函数中,对是否接收到服务器的结果全部返回标识做了判断,并断开与服务器的连接

using HandyControl.Controls;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace HandyControlTest
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : System.Windows.Window
    {
        recorder r = new recorder();
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            r.SendFileToWebSocket();
            r.receiveMessage();
        }
    }
}

class recorder
{
    private string _appID = "6f28cdb3";
    private string _apiSecret = "Mzc3OWJjYjQxYjI5YzVhNWMwYzdiNmFk";
    private string _apiKey = "bf7d03b453328d790a0d2efabe47a1db";
    private string _wss = "wss://iat-api.xfyun.cn/v2/iat";
    private string _host = "iat-api.xfyun.cn";
    private string _request_line = "GET /v2/iat HTTP/1.1";
    private bool _isConnected = false;//连接服务器标志位
    private bool _isSendDone = false;//已经完成发送
    private WebSocket _ws;

    //创建url
    private string GetUrl()
    {
        string date = DateTime.Now.ToString("R");
        string signature_origin = $"host: {_host}\ndate: {date}\n{_request_line}";
        HMACSHA256 mac = new HMACSHA256(Encoding.UTF8.GetBytes(_apiSecret));
        string signature = Convert.ToBase64String(mac.ComputeHash(Encoding.UTF8.GetBytes(signature_origin)));
        string authorization_origin = $"api_key=\"{_apiKey}\",algorithm=\"hmac-sha256\",headers=\"host date request-line\",signature=\"{signature}\"";
        string authorization = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization_origin));
        string url = $"{_wss}?authorization={authorization}&date={date}&host={_host}";
        return url;
    }

    //连接WebSocket服务器
    private async void ConnectWebSocket()
    {
        try
        {
            Uri url = new Uri(this.GetUrl());
            ClientWebSocket webSocket = new ClientWebSocket();
            CancellationToken ct = new CancellationToken();
            await webSocket.ConnectAsync(url, ct);
            _isConnected = true;
            _ws = webSocket;
        }
        catch (Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message);
        }
    }

    //发送音频至服务器
    public async void SendFileToWebSocket()
    {
        int frameSize = 6400;//每次发送音频字节数6400B
        int intervel = 5;//每次发送音频间隔5ms
        int pcmCount = 0;//记录音频已发送的大小
        int pcmSize = 0;//剩余音频大小
        int status = 0;//音频的发送状态;0:第一帧;1:继续帧;2:最后一帧
        string filePath = "E:\\SystemData\\desktop\\recorded.wav";//录音文件路径

        ConnectWebSocket();

        try
        {
            while (!_isConnected)
            {
                await Task.Delay(intervel);//异步等待服务器连接
            }

            byte[] arr = File.ReadAllBytes(filePath);//读取文件所有字节
            if (arr == null)
            {
                return;
            }

            pcmSize = arr.Length;//获取音频总长
            while (true)
            {
                if (pcmSize <= frameSize)//若剩余音频小于等于1280B,则视为最后帧发送
                {
                    frameSize = pcmSize;
                    status = 2;
                    if (frameSize <= 0)
                        break;
                }
                byte[] buffer = new byte[frameSize];
                Array.Copy(arr, pcmCount, buffer, 0, frameSize);
                pcmCount += frameSize;
                pcmSize -= frameSize;
                switch (status)
                {
                    case 0:
                        onSend(0, Convert.ToBase64String(buffer));
                        status = 1;
                        break;

                    case 1:
                        onSend(1, Convert.ToBase64String(buffer));
                        break;

                    case 2:
                        onSend(1, Convert.ToBase64String(buffer));
                        onSend(2, null);//告诉服务器已经发送结束,本应该需要隔40ms再发送
                        _isSendDone = true;
                        break;
                }
                await Task.Delay(intervel);//延时40ms
            }
        }
        catch (Exception e)
        {
            System.Windows.MessageBox.Show(e.Message);
        }
    }

    //每次发送数据
    //curStatus:用于记录发送过程
    //0:首次发送;1:发送中;2:结束发送
    private void onSend(int curStatus, string data)
    {
        if (curStatus == 0)
        {
            var json = new
            {
                common = new
                {
                    app_id = $"{_appID}"
                },
                business = new
                {
                    language = "zh_cn",
                    domain = "iat",
                    accent = "mandarin"
                },
                data = new
                {
                    status = 0,
                    format = "audio/L16;rate=16000",
                    encoding = "raw",
                    audio = $"{data}"
                }
            };
            string jsonStr = JsonConvert.SerializeObject(json, Formatting.Indented);
            _ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(jsonStr)), WebSocketMessageType.Binary, true, new CancellationToken());
        }

        else if (curStatus == 1)
        {
            var json = new
            {
                data = new
                {
                    status = 1,
                    format = "audio/L16;rate=16000",
                    encoding = "raw",
                    audio = $"{data}"
                }
            };
            string jsonStr = JsonConvert.SerializeObject(json, Formatting.Indented);
            _ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(jsonStr)), WebSocketMessageType.Binary, true, new CancellationToken());
        }

        else if (curStatus == 2)
        {
            var json = new
            {
                data = new
                {
                    status = 2
                }
            };
            string jsonStr = JsonConvert.SerializeObject(json, Formatting.Indented);
            _ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(jsonStr)), WebSocketMessageType.Binary, true, new CancellationToken());
        }
    }

    public async void receiveMessage()
    {
        while (!_isSendDone)
        {
            await Task.Delay(10);//异步等待服务器连接
        }
        byte[] buffer = new byte[1024];//可以给大一点,如果识别长时间音频可以会出bug
        string str = null;//拼接整句话
        while (_ws.State == WebSocketState.Open)
        {
            WebSocketReceiveResult result = await _ws.ReceiveAsync(new ArraySegment<byte>(buffer),CancellationToken.None);//等待返回结果
            if(result.MessageType == WebSocketMessageType.Text)
            {
                string jsonData = Encoding.UTF8.GetString(buffer,0,result.Count);
                var jsonObject = JsonConvert.DeserializeObject<dynamic>(jsonData);//转换为json格式
                var data = jsonObject["data"]["result"]["ws"];//提取听写结果
                foreach (var item in data)
                {
                    foreach (var item2 in item["cw"])
                    {
                        str += item2["w"];
                    } 
                }
                bool done = jsonObject["data"]["result"]["ls"];//是否完成所有返回结果的接收
                if(done)
                {
                    await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "closing", CancellationToken.None);//断开与服务器的连接
                    _isSendDone = false;
                    _isConnected = false;
                    break;
                }
            }
        }
        HandyControl.Controls.MessageBox.Show(str);
    }
}

         这是我用来实现语音识别的测试,空出来的几个参数是需要自己注册科大讯飞账号然后在控制台获取

private string _appID = ;
private string _apiSecret = ;
private string _apiKey = ;

        科大讯飞对于音频有要求,具体可到官方文档查阅,我使用开源库NAudio能够录制到符合要求的音频

GitHub - naudio/NAudio: Audio and MIDI library for .NET

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF(Windows Presentation Foundation)是一种用于创建Windows桌面应用程序的技术。而WebAPI是一种用于创建Web服务的框架。虽然WPF主要用于构建桌面应用程序,但我们可以使用WPF来生成WebAPI接口。 要生成WebAPI接口,我们可以按照以下步骤进行操作: 1. 创建WPF应用程序项目:在Visual Studio中创建一个新的WPF应用程序项目。 2. 添加WebAPI控制器类:在项目中添加一个控制器类,该类继承自System.Web.Http.ApiController,并实现所需的接口方法。在这些方法中,我们可以定义需要接收的HTTP请求和返回的数据。 3. 配置WebAPI路由:在Global.asax文件中配置WebAPI路由,以将HTTP请求路由到正确的控制器和方法中。 4. 编写业务逻辑:在控制器方法中,根据需求编写业务逻辑,可以连接数据库、调用其他服务等。 5. 运行应用程序:通过调试或发布应用程序,将其运行在本地的IIS或其他Web服务器上。 通过以上步骤,我们可以使用WPF生成WebAPI接口。此时,我们可以通过HTTP请求访问WPF应用程序中的接口,并获取返回的数据。 需要注意的是,尽管我们可以使用WPF来生成WebAPI接口,但这并不是WPF的主要用途。如果只需要创建WebAPI接口,建议使用专门的Web开发框架,如ASP.NET Core等。以上所述仅为一种可能的解决方案,具体实现方式可能因项目需求和框架版本而有所不同。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值