获取Token
using UnityEngine;
using System;
using System.Text;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using UnityEngine.Networking;
using System.Collections.Generic;
using System.Globalization;
using Cysharp.Threading.Tasks;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class AliTTSCtrl : MonoBehaviour
{
private readonly string accessKeyId = "********";
private readonly string accessKeySecret = "********";
private readonly string accessKey = "********";
private readonly string account = "********";
private readonly string regionId = "cn-shanghai";
private readonly string version = "2019-02-28";
private readonly string action = "CreateToken";
private readonly string formatType = "JSON";
private readonly string signatureMethod = "HMAC-SHA1";
private readonly string signatureVersion = "1.0";
private DateTime expirationTime = DateTime.MinValue;
void Start()
{
}
[ContextMenu("获取 Token")]
#if UNITY_EDITOR
[ExecuteInEditMode]
#endif
public async UniTask<string> GetToken()
{
try {
var res = CheckTokenExpireTime();
if (res.Item1)
{
return res.Item2;
}
else
{
var token = await PostTokenRequest();
return token;
}
}catch(Exception e)
{
Debug.LogError($"错误: {e}");
}
throw new NullReferenceException("Token 无法获取");
}
private (bool, string) CheckTokenExpireTime()
{
string tokenString = PlayerPrefs.GetString(accessKeyId, "");
if (!string.IsNullOrEmpty(tokenString))
{
JObject token = JObject.Parse(tokenString);
long expireTime = token["ExpireTime"].Value<long>();
long currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
long timeLeft = expireTime - currentTime;
string tokenID = token["Id"].Value<string>();
if (timeLeft < 86400)
{
Debug.Log("Token 将在24小时内过期 True");
return (false, null);
}
else
{
Debug.Log("Token 还可以使用 False");
return (true, tokenID);
}
}
return (false, null);
}
async UniTask<string> PostTokenRequest()
{
string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture);
string signatureNonce = Guid.NewGuid().ToString();
var parameters = new Dictionary<string, string>
{
{ "AccessKeyId", accessKeyId },
{ "Action", action },
{ "Format", formatType },
{ "RegionId", regionId },
{ "SignatureMethod", signatureMethod },
{ "SignatureNonce", signatureNonce },
{ "SignatureVersion", signatureVersion },
{ "Timestamp", timestamp},
{ "Version", version }
};
string queryString = EncodeDictionary(parameters);
string stringToSign = "GET&" + EncodeText("/") + "&" + EncodeText(queryString);
string signature = CalculateSignature(accessKeySecret, stringToSign);
signature = EncodeText(signature);
string url = $"https://nls-meta.cn-shanghai.aliyuncs.com/?Signature={signature}&{queryString}";
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
var asyncOp = www.SendWebRequest();
await asyncOp;
var header = www.GetResponseHeaders();
string headerStr = "";
headerStr += www.uri.Host+"\n";
foreach (var head in header)
{
headerStr += $"{head.Key} : {head.Value} \n";
}
Debug.Log($"请求 Response: {headerStr}");
if (www.result != UnityWebRequest.Result.Success)
{
string textData = www.downloadHandler.text;
Debug.LogError($"请求错误 Error:{www.result} + {www.error} -> {textData}");
}
else
{
string jsonResponse = www.downloadHandler.text;
Debug.Log($"请求成功 Response: {jsonResponse}");
JObject json = JObject.Parse(jsonResponse);
JToken token = json["Token"];
if (token != null && token["ExpireTime"] != null && token["Id"] != null)
{
PlayerPrefs.SetString(accessKeyId, token.ToString());
PlayerPrefs.Save();
long expireTime = token["ExpireTime"].Value<long>();
long currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
DateTime expiryDateTime = DateTimeOffset.FromUnixTimeSeconds(expireTime).UtcDateTime;
DateTime currentDateTime = DateTimeOffset.FromUnixTimeSeconds(currentTime).UtcDateTime;
TimeSpan timeLeft = expiryDateTime - currentDateTime;
string formattedTime = $"{timeLeft.Days}天 {timeLeft.Hours}小时 {timeLeft.Minutes}分钟 {timeLeft.Seconds}秒";
Debug.Log($"Token 数据保存成功 ; 当前时间:{currentDateTime.ToString("yyyy-MM-dd HH:mm:ss")} - 过期时间:{expiryDateTime.ToString("yyyy-MM-dd HH:mm:ss")} - 有效时长:{formattedTime}");
return token.ToString();
}
else
{
Debug.Log("Token or required 的字段 不足或者丢失!");
}
}
}
return "";
}
private string EncodeText(string text)
{
string encoded = UnityWebRequest.EscapeURL(text)
.Replace("+", "%20")
.Replace("*", "%2A")
.Replace("%7E", "~")
.Replace("%7E", "~");
encoded = System.Text.RegularExpressions.Regex.Replace(encoded, "%[0-9a-f]{2}", m => m.Value.ToUpper());
return encoded;
}
private string EncodeDictionary(Dictionary<string, string> dic)
{
var items = dic.OrderBy(kvp => kvp.Key).Select(kvp =>
$"{EncodeText(kvp.Key)}={EncodeText(kvp.Value)}");
return string.Join("&", items);
}
private string CalculateSignature(string accessKeySecret, string stringToSign)
{
var keyBytes = Encoding.UTF8.GetBytes(accessKeySecret + "&");
var signBytes = Encoding.UTF8.GetBytes(stringToSign);
using (var hmacsha1 = new HMACSHA1(keyBytes))
{
byte[] hashMessage = hmacsha1.ComputeHash(signBytes);
string signature = Convert.ToBase64String(hashMessage);
return signature;
}
}
}
使用阿里云 TTS
using System;
using UnityEngine;
using System.Text.RegularExpressions;
using System.Net.Http;
using System.IO;
using UnityEngine.Networking;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks;
[Serializable]
public class Header
{
public string message_id;
public string task_id;
public string @namespace;
public string name;
public string appkey;
}
public class VoiceSynthesis : MonoBehaviour
{
private AliTTSCtrl aliTTSCtrl;
private TTSGeneral tTSGeneral;
private AudioSource audioSource;
void Start()
{
aliTTSCtrl = GetComponent<AliTTSCtrl>();
audioSource = GetComponent<AudioSource>();
}
[ContextMenu("进行TTS")]
#if UNITY_EDITOR
[ExecuteInEditMode]
#endif
private async UniTask TTS()
{
if (aliTTSCtrl == null)
{
aliTTSCtrl = GetComponent<AliTTSCtrl>();
}
if (audioSource == null)
{
audioSource = GetComponent<AudioSource>();
}
var token = await aliTTSCtrl.GetToken();
Debug.Log($"Token {token}");
if (tTSGeneral == null)
{
tTSGeneral = new TTSGeneral("******", token, audioSource);
}
await tTSGeneral.SpeakAsync();
}
void OnDestroy()
{
}
private void OnApplicationQuit()
{
}
}
public class TTSGeneral
{
private string appKey = "";
private string accessToken = "";
private AudioSource audioSource;
private string ttsUrl = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
private string v;
private UniTask<string> token;
public TTSGeneral(
string appKey,
string accessToken,
AudioSource audioSource)
{
this.appKey = appKey;
this.accessToken = accessToken;
this.audioSource = audioSource;
}
public async UniTask<string> SynthesizeSpeech(
string text,
string format = "wav",
int sampleRate = 16000,
string voice = "siyue")
{
try
{
using (var client = new HttpClient())
{
var url = $"{ttsUrl}?appkey={appKey}&token={accessToken}&text={Uri.EscapeDataString(text)}&format={format}&sample_rate={sampleRate}&voice={voice}";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
byte[] audioBytes = await response.Content.ReadAsByteArrayAsync();
string path = Path.Combine(Application.persistentDataPath, "output.wav");
File.WriteAllBytes(path, audioBytes);
return path;
}
}
catch (Exception ex)
{
Debug.LogError($"Error synthesizing speech: {ex.Message}");
throw;
}
}
public async UniTask SpeakAsync()
{
string textToSpeak = "采用最先进的端到端语音识别框架,字错误率相比上一代系统相对下降10%至30%,并发推理速度相比业内主流推理推理框架提升10倍以上,同时支持实时和离线语音识别,毫秒级延迟。";
string audioFilePath = null;
try
{
audioFilePath = await SynthesizeSpeech(textToSpeak);
}
catch (Exception ex)
{
Debug.LogError($"Error during speech synthesis: {ex.Message}");
}
if (!string.IsNullOrEmpty(audioFilePath))
{
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + audioFilePath, AudioType.WAV))
{
DownloadHandlerAudioClip downloadHandler = www.downloadHandler as DownloadHandlerAudioClip;
downloadHandler.streamAudio = true;
await www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
AudioClip clip = downloadHandler.audioClip;
if (audioSource != null)
{
audioSource.clip = clip;
audioSource.Play();
}
else
{
Debug.LogError($"必须有 AudioSource 组件才可以播放");
}
}
else
{
Debug.LogError($"Failed to load audio file: {www.error}");
}
}
}
}
}
使用阿里云 OCR
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Imagine.WebAR;
using Cysharp.Threading.Tasks;
using Tea;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Ocr_api20210707.Models;
using AlibabaCloud.TeaUtil.Models;
using AlibabaCloud.SDK.Ocr_api20210707;
using AlibabaCloud.TeaUtil;
using AlibabaCloud.OpenApiClient;
using AlibabaCloud.OpenApiUtil;
using System.Reflection;
public class AliOCR : MonoBehaviour
{
public Texture2D texture;
public RenderTexture textureRender;
private OCRUnified oCR;
private TextureExtractor_WarpedImage warpedImage;
private readonly string accessKeyId = "********";
private readonly string accessKeySecret = "********";
void Start()
{
if (oCR == null)
{
oCR = new OCRUnified(accessKeyId, accessKeySecret);
}
warpedImage = GetComponent<TextureExtractor_WarpedImage>();
}
public void OnImageFound(string id)
{
if (warpedImage == null)
{
warpedImage = GetComponent<TextureExtractor_WarpedImage>();
}
warpedImage.ExtractTexture(id);
Debug.Log($"执行 OCR 识别.....");
try
{
OCR();
}
catch (Exception ex)
{
Debug.LogError("OCR failed 2 : " + ex.Message);
}
}
public void OnImageLost(string id)
{
}
[ContextMenu("进行ORC")]
#if UNITY_EDITOR
[ExecuteInEditMode]
#endif
private void OCR()
{
Debug.Log($"执行 OCR 识别2 .....");
if (oCR == null)
{
oCR = new OCRUnified(accessKeyId, accessKeySecret);
}
try
{
var imaStream = RenderTextureAsync();
string res = oCR.Run(imaStream);
if (res == "")
{
Debug.Log($"没有识别到任何文字:{res}");
}
else
{
Debug.Log($"识别到文字:{res}");
}
imaStream.Close();
}
catch (Exception ex)
{
Debug.LogError("OCR failed2 : " + ex.Message);
}
}
private Stream RenderTextureAsync()
{
RenderTexture.active = textureRender;
Texture2D texture2D = new Texture2D(textureRender.width, textureRender.height, TextureFormat.RGB24, false);
texture2D.ReadPixels(new Rect(0, 0, textureRender.width, textureRender.height), 0, 0);
texture2D.Apply();
RenderTexture.active = null;
byte[] jpgData = texture2D.EncodeToJPG();
#if UNITY_EDITOR
DestroyImmediate(texture2D);
#else
Destroy(texture2D);
#endif
return new MemoryStream(jpgData);
}
}
public class OCRUnified
{
private AlibabaCloud.OpenApiClient.Client aliClient;
private AlibabaCloud.SDK.Ocr_api20210707.Client aliClient2;
public OCRUnified(string accessKeyId, string accessKeySecret)
{
aliClient = CreateClient(accessKeyId, accessKeySecret);
aliClient2 = CreateClient2(accessKeyId, accessKeySecret);
}
public string Run(Stream textureBody)
{
try
{
Debug.Log($"执行 OCR 识别3 .....");
AlibabaCloud.OpenApiClient.Models.Params params_ = CreateApiInfo();
Debug.Log($" 1 OCR 创建 API 成功 .....");
Dictionary<string, object> queries = new Dictionary<string, object>() { };
queries["Type"] = "Advanced";
queries["OutputFigure"] = true;
AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
Debug.Log($" 2 OCR 创建 RuntimeOptions 成功 .....");
AlibabaCloud.OpenApiClient.Models.OpenApiRequest request = new AlibabaCloud.OpenApiClient.Models.OpenApiRequest
{
Query = AlibabaCloud.OpenApiUtil.Client.Query(queries),
Stream = textureBody,
};
Debug.Log($" 3 OCR 创建 OpenApiRequest 成功 .....");
Dictionary<string, object> res = null;
try
{
Debug.Log($"params : {ConvertToJson(params_)}");
Debug.Log($"request : {ConvertToJson(request)}");
Debug.Log($"runtime : {ConvertToJson(runtime)}");
res = aliClient.CallApi(params_, request, runtime);
}
catch (Exception ex)
{
Debug.LogError($"CallApi 错误 {ex}");
}
Debug.Log($" 4 OCR 请求 成功 .....");
string jsonString = JsonConvert.SerializeObject(res, Formatting.Indented);
if (res.ContainsKey("statusCode"))
{
var statusCode = res["statusCode"];
int code = int.Parse(statusCode.ToString());
if (code == 200)
{
Debug.Log(jsonString);
JObject jsonObject = JObject.Parse(jsonString);
string content = jsonObject["body"]["Data"]["Content"].ToString();
Debug.Log($"content = {content}");
return content;
}
else
{
var strRes = $"识别异常 {code} -> {jsonString} ";
Debug.LogError(strRes);
return strRes;
}
}
return $"不是有效的返回 {jsonString}";
}
catch (Exception ex)
{
var strRes = $"ORC 错误: {ex}";
Debug.LogError(strRes);
return strRes;
}
}
public static string ConvertToJson(object obj)
{
var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
var result = new System.Text.StringBuilder();
result.Append("{");
bool first = true;
foreach (var property in properties)
{
if (!first)
{
result.Append(", ");
}
else
{
first = false;
}
try
{
var value = property.GetValue(obj, null);
string jsonValue = value != null ? value.ToString() : "null";
result.AppendFormat("\"{0}\": {1}", property.Name, jsonValue);
}
catch (Exception ex)
{
result.AppendFormat("\"{0}\": \"Error: {1}\"", property.Name, ex.Message);
}
}
result.Append("}");
return result.ToString();
}
public static void PrintJson(object obj)
{
Debug.Log(ConvertToJson(obj));
}
public AlibabaCloud.OpenApiClient.Client CreateClient(string accessKeyId, string accessKeySecret)
{
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
{
AccessKeyId = accessKeyId,
AccessKeySecret = accessKeySecret
};
config.Endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
return new AlibabaCloud.OpenApiClient.Client(config);
}
public AlibabaCloud.SDK.Ocr_api20210707.Client CreateClient2(string accessKeyId, string accessKeySecret)
{
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
{
AccessKeyId = accessKeyId,
AccessKeySecret = accessKeySecret,
};
config.Endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
return new AlibabaCloud.SDK.Ocr_api20210707.Client(config);
}
public string Run2(Stream textureBody)
{
Stream bodyStream = AlibabaCloud.DarabonbaStream.StreamUtil.ReadFromFilePath("<your-file-path>");
var dd = new AlibabaCloud.SDK.Ocr_api20210707.Models.DataSubImagesFigureInfoValue();
AlibabaCloud.SDK.Ocr_api20210707.Models.RecognizeAllTextRequest recognizeAllTextRequest = new AlibabaCloud.SDK.Ocr_api20210707.Models.RecognizeAllTextRequest
{
Type = "Advanced",
OutputFigure = true,
Body = textureBody,
};
AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
try
{
recognizeAllTextRequest.Validate();
Debug.Log($" 验证通过 ");
var res = aliClient2.RecognizeAllTextWithOptions(recognizeAllTextRequest, runtime);
return res.Body.Data.Content;
}
catch (TeaException error)
{
Debug.Log($"Tea错误 : {error.Message}");
Debug.Log($"Tea错误2 : {error.Data["Recommend"]}");
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
}
catch (Exception _error)
{
Debug.Log($"错误 : {_error}");
TeaException error = new TeaException(new Dictionary<string, object>
{
{ "message", _error.Message }
});
Debug.Log($"错误2 : {error.Message}");
Debug.Log($"错误3 : {error.Data["Recommend"]}");
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
}
return "";
}
public AlibabaCloud.OpenApiClient.Models.Params CreateApiInfo()
{
AlibabaCloud.OpenApiClient.Models.Params params_ = new AlibabaCloud.OpenApiClient.Models.Params
{
Action = "RecognizeAllText",
Version = "2021-07-07",
Protocol = "HTTPS",
Method = "POST",
AuthType = "AK",
Style = "V3",
Pathname = "/",
ReqBodyType = "json",
BodyType = "json",
};
return params_;
}
public void RecognizeAllTextWithOptions()
{
}
}