获取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]
#endifpublic 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]
#endifprivate 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]
#endifprivate 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_EDITORDestroyImmediate(texture2D);
#elseDestroy(texture2D);
#endifreturn 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(){}}