Unity调用科大讯飞声纹识别接口解决方案详细说明
声纹识别是根据人的声音特征进行验证的一项技术
·
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
声纹识别(Voiceprint Recognition),是一项提取说话人声音特征和说话内容信息,自动核验说话人身份的技术。可以将说话人声纹信息与库中的已知用户声纹进行1:1比对验证和1:N的检索,当声纹匹配时即为验证/检索成功。
一、接口流程是什么?
科大讯飞控制台地址:https://passport.xfyun.cn/login
1.文档地址:https://www.xfyun.cn/doc/voiceservice/isv/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B
2.要求
1、创建声纹特征库(必须)
2、添加音频特征(必须)
3、特征比对1:1(必须)
4、特征比对1:N(必须)
5、查询特征列表(非必须)
6、更新音频特征(非必须)
7、删除指定特征(非必须)
8、删除声纹特征库(非必须)
二、使用步骤
1.构建URL
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using UnityEngine;
public class GenerateRequestUrl
{
public const string APPID = "xxxx";
public const string APISECRET = "xxxxxx";
public const string APIKEY = "xxxxxx";
public string AppId { get { return APPID; } }
// 生成SHA256哈希并使用Base64编码
public string Sha256Base64(string data)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(data));
return Convert.ToBase64String(bytes);
}
}
// 解析URL以获取主机和路径
public void ParseUrl(string requestUrl, out string host, out string path)
{
int startIndex = requestUrl.IndexOf("://", StringComparison.Ordinal);
if (startIndex == -1)
throw new ArgumentException("Invalid request URL format.", nameof(requestUrl));
string afterProtocol = requestUrl.Substring(startIndex + 3);
int endIndex = afterProtocol.IndexOf('/', StringComparison.Ordinal);
if (endIndex <= 0)
throw new Exception("Invalid request URL: " + requestUrl);
host = afterProtocol.Substring(0, endIndex);
path = afterProtocol.Substring(endIndex);
}
// 组装WebSocket授权请求URL
public string AssembleWsAuthUrl(string requestUrl, string apiKey, string apiSecret, string method = "POST")
{
string host, path;
ParseUrl(requestUrl, out host, out path);
DateTime now = DateTime.UtcNow;
string date = now.ToString("r"); // RFC1123 format, close enough to what format_date_time does in Python/WSGI
string signatureOrigin = $"host: {host}\ndate: {date}\n{method} {path} HTTP/1.1";
byte[] secretBytes = Encoding.UTF8.GetBytes(apiSecret);
byte[] signatureOriginBytes = Encoding.UTF8.GetBytes(signatureOrigin);
using (HMACSHA256 hmac = new HMACSHA256(secretBytes))
{
byte[] signatureBytes = hmac.ComputeHash(signatureOriginBytes);
string signatureSha = Convert.ToBase64String(signatureBytes);
string authorizationOrigin = $"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signatureSha}\"";
string authorization = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorizationOrigin));
// Construct the final request URL with authorization parameters
string encodedAuthBase = WebUtility.UrlEncode(authorization);
string encodedHost = WebUtility.UrlEncode(host);
string encodedDate = WebUtility.UrlEncode(date);
string finalUrl = $"{requestUrl}?authorization={encodedAuthBase}&host={encodedHost}&date={encodedDate}";
return finalUrl;
}
}
public string BuildRequestUrl(string requestUrl, string apiKey,string apiSecret)
{
try
{
// Replace ws or wss schema with http or https
string httpRequestUrl = requestUrl.Replace("ws://", "http://").Replace("wss://", "https://");
Uri url = new Uri(httpRequestUrl);
// Get current date and format it for HTTP header
string date = DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture); // ISO 8601 format
string host = url.Host;
// Uncomment the following block if you need to include the port in the host header
// if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))
// {
// host += $":{url.Port}";
// }
StringBuilder sb = new StringBuilder();
sb.Append("host: ").AppendLine(host);
sb.Append("date: ").AppendLine(date);
sb.Append("POST ").Append(url.AbsolutePath).Append(" HTTP/1.1");
// Compute the HMACSHA256 signature
string sha = string.Empty;
using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
{
byte[] signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
sha = Convert.ToBase64String(signatureBytes);
}
// Prepare the authorization header
string authorization = $"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{sha}\"";
string authBase = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization));
// Construct the final request URL with authorization parameters
string encodedAuthBase = WebUtility.UrlEncode(authBase);
string encodedHost = WebUtility.UrlEncode(host);
string encodedDate = WebUtility.UrlEncode(date);
string finalUrl = $"{requestUrl}?authorization={encodedAuthBase}&host={encodedHost}&date={encodedDate}";
Debug.Log($"finaUrl:{finalUrl}");
return finalUrl;
}
catch (Exception ex)
{
throw new Exception("Error assembling request URL: " + ex.Message);
}
}
/// <summary>
/// 获取接口鉴权请求地址
/// </summary>
public string GetauthorizationUr(GenerateRequestUrl genReqUrl)
{
string apiKey = APIKEY;
string apiSecret = APISECRET;
string requestUrl = "https://api.xf-yun.com/v1/private/s782b4996";
string authUrl = genReqUrl.AssembleWsAuthUrl(requestUrl, apiKey, apiSecret);
return (authUrl);
}
}
2.创建声纹特征库
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
/// <summary>
/// 创建声纹特征库
/// </summary>
public class CreateGroup : MonoBehaviour
{
private static string currentState = string.Empty;//当前识别状态
public static string CurrentState { get => currentState; set => currentState = value; }
private IEnumerator GenerateCreateGroup()
{
GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
CurrentState = string.Empty;
string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
Debug.Log($"url:{url}");
var param = new JsonParse
{
header = new Header()
{
app_id = "xxxx",
status = 3
},
parameter = new Parameter()
{
s782b4996 = new S782b4996()
{
func = "createGroup",
groupId = "iFLYTEK_examples_groupId",
groupName= "iFLYTEK_examples_groupName",
groupInfo= "iFLYTEK_examples_groupInfo",
createGroupRes=new CreateGroupRes()
{
encoding = "utf8",
compress="raw",
format="json"
}
}
}
};
string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。
byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
using (UnityWebRequest webRequest = UnityWebRequest.Post(url, paramsJson))
{
using (var uh = new UploadHandlerRaw(bodyRaw))
{
webRequest.uploadHandler.Dispose();
webRequest.uploadHandler = uh;
//webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SetRequestHeader("Accept", "*/*");
yield return webRequest.SendWebRequest();
}
while (!webRequest.isDone) { yield return null; }
if (webRequest.result == UnityWebRequest.Result.Success)
{
try
{
// 在这里处理你的返回数据,比如解析JSON等。
// 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。
// 你可能需要调用另一个方法来处理这个返回的数据。
string responseText = webRequest.downloadHandler.text;
Logging.Info($"Response: {responseText}");
var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
string txt = result.payload.createGroupRes.text;
Logging.Info($"txt: {txt}");
byte[] decodedBytes = Convert.FromBase64String(txt);
string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);
Debug.Log($"textBase64Decode:{textBase64Decode}");
if (textBase64Decode.Equals("success"))
{
print("创建库成功");
}
else
{
print("创建库失败");
}
}
catch (Exception ex)
{
webRequest.Abort();
webRequest.Dispose();
Logging.Error($"创建声纹特征库失败:{ex.Message}");
}
}
else if (webRequest.result == UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError)
{
webRequest.Dispose();
}
}
}
[SerializeField]
//Json解析
public class JsonParse
{
public Header header { get; set;}
public Parameter parameter { get; set; }
}
[SerializeField]
public class Parameter
{
public S782b4996 s782b4996 { get; set; }
}
[SerializeField]
public class Header
{
public string app_id { get; set; }
public int status { get; set; }
}
[SerializeField]
public class S782b4996
{
public string func { get; set; }
public string groupId { get; set; }
public string groupName { get; set; }
public string groupInfo { get; set; }
//根据model的取值不同,名字有所变动。
public CreateGroupRes createGroupRes { get; set; }
}
[SerializeField]
public class CreateGroupRes
{
public string compress { get; set; }
public string encoding { get; set; }
public string format { get; set; }
}
[SerializeField]
public class Header2
{
public int code { get; set; }
public string message { get; set; }
public string sid { get; set; }
}
[SerializeField]
public class CreateGroupRes2
{
public string text { get; set; }
}
[SerializeField]
public class Payload2
{
public CreateGroupRes2 createGroupRes;
}
[SerializeField]
public class PlayParamerter
{
public Header2 header { get; set; }
public Payload2 payload { get; set; }
}
}
2.添加音频特征
代码如下(示例):
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// 创建声纹特征库
/// </summary>
public class CreateFeature : MonoBehaviour
{
private IEnumerator GenerateCreateFeature()
{
GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
// 音频文件路径
string audioFilePath = Application.streamingAssetsPath + "/music/dd.mp3";
// 读取音频文件为字节数组
byte[] audioBytes = File.ReadAllBytes(audioFilePath);
// 对音频字节数组进行Base64编码
string base64StringAudio = Convert.ToBase64String(audioBytes);
string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
Debug.Log($"url:{url}");
var param = new JsonParse
{
header = new Header()
{
app_id = "xxxx",
status = 3
},
parameter = new Parameter()
{
s782b4996 = new S782b4996()
{
func = "createFeature",
groupId = "iFLYTEK_examples_groupId",
featureId= "iFLYTEK_examples_featureId",
featureInfo = "iFLYTEK_examples_featureInfo",
createFeatureRes = new CreateFeatureRes()
{
encoding = "utf8",
compress="raw",
format="json"
}
}
},
payload = new PayLoad()
{
resource = new Resource()
{
encoding = "lame",
sample_rate = 16000,
channels=1,
bit_depth=16,
status=3,
audio= base64StringAudio
}
}
};
string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。
byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
using (UnityWebRequest webRequest =UnityWebRequest.Post(url, paramsJson))
{
using (var uh = new UploadHandlerRaw(bodyRaw))
{
webRequest.uploadHandler.Dispose();
webRequest.uploadHandler = uh;
//webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SetRequestHeader("Accept", "*/*");
yield return webRequest.SendWebRequest();
}
while (!webRequest.isDone) { yield return null; }
if (webRequest.result == UnityWebRequest.Result.Success)
{
try
{
// 在这里处理你的返回数据,比如解析JSON等。
// 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。
// 你可能需要调用另一个方法来处理这个返回的数据。
string responseText = webRequest.downloadHandler.text;
Debug.Log($"Response: {responseText}");
var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
string txt = result.payload.createFeatureRes.text;
byte[] decodedBytes = Convert.FromBase64String(txt);
string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);
if (result.header.message.Equals("success"))
{
//识别成功
}
else
{
//识别失败
}
Logging.Debug($"textBase64Decode:{textBase64Decode}");
}
catch (Exception ex)
{
Logging.Error($"创建声纹特征库失败:{ex.Message}");
}
}
else if (webRequest.result == UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError)
{
webRequest.Dispose();
}
}
}
[SerializeField]
//Json解析
public class JsonParse
{
public Header header { get; set;}
public Parameter parameter { get; set; }
public PayLoad payload { get; set; }
}
[SerializeField]
public class Parameter
{
public S782b4996 s782b4996 { get; set; }
}
[SerializeField]
public class Header
{
public string app_id { get; set; }
public int status { get; set; }
}
[SerializeField]
public class S782b4996
{
public string func { get; set; }
public string groupId { get; set; }
public string featureId { get; set; }
public string featureInfo { get; set; }
//根据model的取值不同,名字有所变动。
public CreateFeatureRes createFeatureRes { get; set; }
}
[SerializeField]
public class CreateFeatureRes
{
public string compress { get; set; }
public string encoding { get; set; }
public string format { get; set; }
}
[SerializeField]
public class PayLoad
{
public Resource resource { get; set; }
}
[SerializeField]
public class Resource
{
public string encoding { get; set; }
public int sample_rate { get; set; }
public int channels { get; set; }
public int bit_depth { get; set; }
public int status { get; set; }
public string audio { get; set; }
}
[SerializeField]
public class Header2
{
public int code { get; set; }
public string message { get; set; }
public string sid { get; set; }
}
[SerializeField]
public class CreateFeatureRes2
{
public string text { get; set; }
}
[SerializeField]
public class Payload2
{
public CreateFeatureRes2 createFeatureRes;
}
[SerializeField]
public class PlayParamerter
{
public Header2 header { get; set; }
public Payload2 payload { get; set; }
}
}
3.特征比对1:1
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
/// <summary>
///特征比对1:1
/// </summary>
public class SearchOneFeature : MonoBehaviour
{
/// <summary>
/// 删除创建声纹特征库
/// </summary>
public void StartSearchOneFeature()
{
StartCoroutine("GenerateSearchOneFeature");
}
private IEnumerator GenerateSearchOneFeature()
{
GenerateRequestUrl generateRequestUrl = new GenerateRequestUrl();
// 音频文件路径
string audioFilePath = Application.streamingAssetsPath + "/music/dd.mp3";
// 读取音频文件为字节数组
byte[] audioBytes = File.ReadAllBytes(audioFilePath);
// 对音频字节数组进行Base64编码
string base64String = Convert.ToBase64String(audioBytes);
string url = generateRequestUrl.GetauthorizationUr(generateRequestUrl);//构建URL
Debug.Log($"url:{url}");
var param = new JsonParse
{
header = new Header()
{
app_id = "xxxx",
status = 3
},
parameter = new Parameter()
{
s782b4996 = new S782b4996()
{
func = "searchScoreFea",
groupId = "iFLYTEK_examples_groupId",
dstFeatureId= "iFLYTEK_examples_featureId",
searchScoreFeaRes = new SearchScoreFeaRes()
{
encoding = "utf8",
compress="raw",
format="json"
}
}
},
payload = new PayLoad()
{
resource = new Resource()
{
encoding = "lame",
sample_rate = 16000,
channels=1,
bit_depth=16,
status=3,
audio= base64String
}
}
};
string paramsJson = JsonConvert.SerializeObject(param); // 假设这是你的参数构建方法,需要你自己实现。
byte[] bodyRaw = Encoding.UTF8.GetBytes(paramsJson);
using (UnityWebRequest webRequest = new UnityWebRequest(url, "POST"))
{
webRequest.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SetRequestHeader("Accept", "*/*");
yield return webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.ConnectionError || webRequest.result != UnityWebRequest.Result.ProtocolError)
{
try
{
// 在这里处理你的返回数据,比如解析JSON等。
// 注意:由于这个方法是Coroutine,你不能直接从DoRequest返回结果。
// 你可能需要调用另一个方法来处理这个返回的数据。
string responseText = webRequest.downloadHandler.text;
ConfigInfo configInfo = new ConfigInfo();
Debug.Log($"Response: {responseText}");
if (!string.IsNullOrEmpty(responseText))
{
var result = JsonConvert.DeserializeObject<PlayParamerter>(responseText);
string txt = result.payload.searchScoreFeaRes.text;
print($"result.header.code:{result.header.code}");
if (result.header.code.Equals(0))
{
byte[] decodedBytes = Convert.FromBase64String(txt);
string textBase64Decode = Encoding.UTF8.GetString(decodedBytes);
Logging.Debug($"textBase64Decode:{textBase64Decode}");
var result2 = JsonConvert.DeserializeObject<JsonTxt>(textBase64Decode);
if (result2.score >= 0.7)//权重值
{
Debug.Log("识别成功");
}
else
{
Debug.Log("识别失败");
}
}
else
{
Debug.Log("识别失败");
}
}
else
{
Debug.Log("识别失败");
}
}
catch (Exception ex)
{
Debug.Log("识别失败");
}
}
else
{
Debug.Log("Received: " + webRequest.downloadHandler.text);
}
webRequest.Dispose();
}
}
[SerializeField]
//Json解析
public class JsonParse
{
public Header header { get; set;}
public Parameter parameter { get; set; }
public PayLoad payload { get; set; }
}
[SerializeField]
public class Parameter
{
public S782b4996 s782b4996 { get; set; }
}
[SerializeField]
public class Header
{
public string app_id { get; set; }
public int status { get; set; }
}
[SerializeField]
public class S782b4996
{
public string func { get; set; }
public string groupId { get; set; }
public string dstFeatureId { get; set; }
//根据model的取值不同,名字有所变动。
public SearchScoreFeaRes searchScoreFeaRes { get; set; }
}
[SerializeField]
public class SearchScoreFeaRes
{
public string compress { get; set; }
public string encoding { get; set; }
public string format { get; set; }
}
[SerializeField]
public class PayLoad
{
public Resource resource { get; set; }
}
[SerializeField]
public class Resource
{
public string encoding { get; set; }
public int sample_rate { get; set; }
public int channels { get; set; }
public int bit_depth { get; set; }
public int status { get; set; }
public string audio { get; set; }
}
[SerializeField]
public class Header2
{
public int code { get; set; }
public string message { get; set; }
public string sid { get; set; }
}
[SerializeField]
public class SearchScoreFeaRes2
{
public string text { get; set; }
}
[SerializeField]
public class Payload2
{
public SearchScoreFeaRes2 searchScoreFeaRes;
}
[SerializeField]
public class PlayParamerter
{
public Header2 header { get; set; }
public Payload2 payload { get; set; }
}
[SerializeField]
public class JsonTxt
{
public float score { get; set; }
public string featureInfo { get; set; }
public string featureId { get; set; }
}
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了科大讯飞声纹识别的使用,而科大讯飞提供了大量能使我们快速便捷地处理数据的接口,谢谢大家的观看,我们下期再见。
更多推荐
所有评论(0)