【數字人開發】Unity+百度智能云平臺實現長短文本個性化語音生成功能

一、創建自己的應用

百度智能云控制臺網址:https://console.bce.baidu.com/

1、創建應用

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2、獲取APIKey和SecretKey

在這里插入圖片描述

3、Api調試

調試網址:https://console.bce.baidu.com/support/?timestamp=1750317430400#/api?product=AI&project=%E8%AF%AD%E9%9F%B3%E6%8A%80%E6%9C%AF&parent=%E9%89%B4%E6%9D%83%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6&api=oauth%2F2.0%2Ftoken&method=post
在這里插入圖片描述

二、在Unity中進行調用

1、相關參數說明

(1)短文本個性化語音生成相關參數

在這里插入圖片描述

(2)長文本個性化語音生成相關參數

在這里插入圖片描述

2、完整代碼

using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class TTS : MonoBehaviour
{#region 相關參數[Header("鑒權相關參數")][SerializeField] private string apiKey = "LFfK6DTaswy6LLtBqvHO86w0";[SerializeField] private string secretKey = "vj6JmKd7zBylDVGW2WmTNPWl9eKxxZEL";[SerializeField] private string accessToken = null;[Space][Header("長文本語音合成參數設置")][SerializeField] private string format = "mp3-16k"; // 或者 wav[SerializeField] private int voice = 0; // 語音人:0-女,1-男等[SerializeField] private string lang = "zh";[SerializeField] private int speed = 5; // 0~15[SerializeField] private int pitch = 5; // 0~15[SerializeField] private int volume = 5; // 0~15[SerializeField] private int enable_subtitle = 0;[Space][Header("短文本語音合成參數設置")][SerializeField] private string cuid = "240a906f2b88794fd0426442c4136a5a57bf5c01";[SerializeField] private string ctp = "1";[SerializeField] private string lan = "zh";[SerializeField] private string spd = "5";[SerializeField] private string pit = "5";[SerializeField] private string vol = "10";[SerializeField] private string per = "1";[SerializeField] private string aue = "3";[Space][Header("UI界面相關")]public InputField inputFieldText;public Button buttonStartTTS;//開始合成按鈕public Button buttonPlay;//播放合成的語音按鈕public AudioSource audioSource;//播放音頻組件#endregion// Start is called before the first frame updatevoid Start(){//一開始就進行鑒權StartCoroutine(GetAccessToken());//語音合成buttonStartTTS.onClick.AddListener(()=> {StartTTS(inputFieldText.text, audioSource);});//播放語音buttonPlay.onClick.AddListener(() =>{if (audioSource.clip != null){audioSource.Play();}});}/// <summary>/// 長短語音合成方法/// </summary>/// <param name="text">要合成的文本內容</param>/// <param name="audioSource">語音組件</param>public void StartTTS(string text,AudioSource audioSource){if (text.Length<60){print("開始短文本語音合成");//短文本語音合成StartCoroutine(ShortTTS(text, response => {audioSource.clip = response.clip;print("短文本語音合成結束,請播放");}));}else{print("開始長文本語音合成");//長文本語音合成StartCoroutine(LongTTS(text, clip=> { audioSource.clip = clip;print("長文本語音合成結束,請播放");}));}}#region 鑒權相關/// <summary>/// 鑒權方法/// </summary>/// <returns></returns>/// <summary>/// 獲取百度 AccessToken(已使用 using 自動釋放資源)/// </summary>public IEnumerator GetAccessToken(){string url = "https://aip.baidubce.com/oauth/2.0/token";WWWForm form = new WWWForm();form.AddField("grant_type", "client_credentials");form.AddField("client_id", apiKey);form.AddField("client_secret", secretKey);using (UnityWebRequest request = UnityWebRequest.Post(url, form)){yield return request.SendWebRequest();if (request.result == UnityWebRequest.Result.Success){try{var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(request.downloadHandler.text);accessToken = tokenResponse.access_token;Debug.Log("? 獲取語音合成 AccessToken 成功: " + accessToken);}catch (Exception ex){Debug.LogError("? 語音合成AccessToken 解析失敗: " + ex.Message);}}else{Debug.LogError("? 獲取 語音合成AccessToken 失敗: " + request.error);}}}#endregion#region 短文本語音合成相關/// <summary>/// 請求短文本語音合成(MP3格式)/// </summary>/// <param name="text">需要合成的文本</param>/// <param name="callback">返回結果回調</param>public IEnumerator ShortTTS(string text, Action<TtsResponse> callback){string url = "http://tsn.baidu.com/text2audio";var param = new Dictionary<string, string>{{ "tex", text },{ "tok", accessToken },{ "cuid", cuid},{ "ctp", ctp},{ "lan", lan},{ "spd", spd},{ "pit", pit},{ "vol", vol},{ "per", per},{ "aue", aue} // 固定為 MP3 格式};// 構建請求 URLint i = 0;foreach (var p in param){url += i != 0 ? "&" : "?";url += p.Key + "=" + UnityWebRequest.EscapeURL(p.Value);i++;}using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG)){//Debug.Log("[TTS] 請求URL: " + www.url);//測試使用yield return www.SendWebRequest();if (www.result != UnityWebRequest.Result.Success){Debug.LogError("[TTS] 請求失敗: " + www.error);callback?.Invoke(new TtsResponse{error_index = -1,error_msg = www.error});}else{string type = www.GetResponseHeader("Content-Type");//Debug.Log("[TTS] Content-Type: " + type);//測試使用if (!string.IsNullOrEmpty(type) && type.Contains("audio")){AudioClip clip = DownloadHandlerAudioClip.GetContent(www);callback?.Invoke(new TtsResponse { clip = clip });}else{string errorText = Encoding.UTF8.GetString(www.downloadHandler.data);Debug.LogError("[TTS] 文本響應錯誤: " + errorText);callback?.Invoke(new TtsResponse{error_index = -2,error_msg = errorText});}}}}/// <summary>/// 返回的語音合成結果/// </summary>public class TtsResponse{public int error_index;public string error_msg;public string sn;public int idx;public bool Success => error_index == 0;public AudioClip clip;}#endregion#region 長文本語音合成相關/// <summary>/// 按順序執行長語音合成對應的方法/// </summary>/// <param name="text">需要合成的文本</param>/// <param name="callback">回調函數,返回合成的clip</param>/// <returns></returns>IEnumerator LongTTS(String text, Action<AudioClip> callback){string taskId = null;//語音合成任務創建成功返回的id//創建語音合成任務yield return StartCoroutine(CreateTTSTask(text,TaskId => { taskId = TaskId; },errorMsg => { Debug.LogError("? 合成失敗: " + errorMsg); }));if (taskId != null && accessToken != null){string audioUrl = null;//語音合成任務合成成功返回的語音下載鏈接//查詢語音合成任務yield return StartCoroutine(QueryTTSTaskStatus(accessToken, taskId,AudioAddress => { audioUrl = AudioAddress; },errorMsg => {Debug.LogError("? 查詢失敗:" + errorMsg);}));//下載語音,并賦值給指定的AudioSource組件if (audioUrl != null){yield return StartCoroutine(DownloadAudio(audioUrl, clip =>{if (clip != null){callback?.Invoke(clip);}else{Debug.LogError("下載的音頻 Clip 為 null");}}));}}}/// <summary>/// 創建語音合成任務/// </summary>/// <returns>TaskId</returns>public IEnumerator CreateTTSTask(string text, Action<string> onSuccess, Action<string> onError){string url = $"https://aip.baidubce.com/rpc/2.0/tts/v1/create?access_token={accessToken}";var bodyObj = new{text = text,format = format,voice = voice,lang = lang,speed = speed,pitch = pitch,volume = volume,enable_subtitle = enable_subtitle};string jsonBody = JsonConvert.SerializeObject(bodyObj);using (UnityWebRequest request = new UnityWebRequest(url, "POST")){byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);request.uploadHandler = new UploadHandlerRaw(bodyRaw);request.downloadHandler = new DownloadHandlerBuffer();request.SetRequestHeader("Content-Type", "application/json");request.SetRequestHeader("Accept", "application/json");yield return request.SendWebRequest();if (request.result == UnityWebRequest.Result.Success){string responseText = request.downloadHandler.text;Debug.Log("? 創建語音任務返回:" + responseText);if (responseText.Contains("task_id")){var response = JsonConvert.DeserializeObject<TTSTaskSuccessResponse>(responseText);onSuccess?.Invoke(response.TaskId);}else if (responseText.Contains("error_code")){var error = JsonConvert.DeserializeObject<TTSTaskErrorResponse>(responseText);onError?.Invoke(error.ErrorMsg);}else{onError?.Invoke("無法識別的返回內容");}}else{Debug.LogError("? 網絡請求失敗:" + request.error);onError?.Invoke(request.error);}}}/// <summary>/// 語音合成任務查詢/// </summary>/// <param name="accessToken">accessToken</param>/// <param name="taskId">合成任務id</param>/// <param name="onSuccess">合成成功返回音頻鏈接</param>/// <param name="onError">合成失敗返回錯誤碼</param>/// <returns></returns>public IEnumerator QueryTTSTaskStatus(string accessToken, string taskId, Action<string> onSuccess, Action<string> onError){string url = $"https://aip.baidubce.com/rpc/2.0/tts/v1/query?access_token={accessToken}";string jsonBody = JsonConvert.SerializeObject(new { task_ids = new string[] { taskId } });float delaySeconds = 2f;while (true){using (UnityWebRequest request = new UnityWebRequest(url, "POST")){request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonBody));request.downloadHandler = new DownloadHandlerBuffer();request.SetRequestHeader("Content-Type", "application/json");request.SetRequestHeader("Accept", "application/json");yield return request.SendWebRequest();if (request.result == UnityWebRequest.Result.Success){string json = request.downloadHandler.text;var root = JsonConvert.DeserializeObject<TTSQueryResponse>(json);if (root.TasksInfo != null && root.TasksInfo.Count > 0){var task = root.TasksInfo[0];switch (task.TaskStatus){case "Success":if (!string.IsNullOrEmpty(task.TaskResult?.SpeechUrl))onSuccess?.Invoke(task.TaskResult.SpeechUrl);elseonError?.Invoke("合成成功但未返回語音地址");yield break;case "Failure":onError?.Invoke(task.TaskResult?.ErrMsg ?? "未知錯誤");yield break;case "Running":Debug.Log("🎙 正在合成...");yield return new WaitForSeconds(delaySeconds);continue;default:onError?.Invoke("未知狀態:" + task.TaskStatus);yield break;}}else{onError?.Invoke("未找到任務信息");yield break;}}else{onError?.Invoke("網絡錯誤:" + request.error);yield break;}}}}/// <summary>/// 下載音頻,并將音頻賦給指定的AudioSource/// </summary>/// <param name="url">音頻下載鏈接</param>/// <param name="audioSource">要賦給的音頻播放組件</param>/// <returns></returns>public IEnumerator DownloadAudio(string url, Action<AudioClip> onComplete){using (UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG)){yield return request.SendWebRequest();if (request.result == UnityWebRequest.Result.Success){AudioClip clip = DownloadHandlerAudioClip.GetContent(request);if (clip != null){Debug.Log("? 音頻合成結束,等待播放");onComplete?.Invoke(clip); // ? 返回 clip}else{Debug.LogError("? 無法解析音頻 Clip");onComplete?.Invoke(null);}}else{Debug.LogError("? 下載音頻失敗:" + request.error);onComplete?.Invoke(null);}}}[Serializable]public class TokenResponse{/// <summary>/// 鑒權返回的數據JSON結構/// </summary>public string access_token;public int expires_in;}[Serializable]public class TTSTaskSuccessResponse{/// <summary>/// 創建語音合成成功返回的數據JSON結構/// </summary>[JsonProperty("log_id")]public long LogId { get; set; }[JsonProperty("task_id")]public string TaskId { get; set; }[JsonProperty("task_status")]public string TaskStatus { get; set; } // "Running"}[Serializable]public class TTSTaskErrorResponse{/// <summary>/// 創建語音合成成功返回的數據JSON結構/// </summary>[JsonProperty("error_code")]public int ErrorCode { get; set; }[JsonProperty("error_msg")]public string ErrorMsg { get; set; }[JsonProperty("log_id")]public long LogId { get; set; }}[Serializable]public class TTSQueryResponse{[JsonProperty("log_id")]public long LogId { get; set; }[JsonProperty("tasks_info")]public List<TTSQueryTaskInfo> TasksInfo { get; set; }}[Serializable]public class TTSQueryTaskInfo{[JsonProperty("task_id")]public string TaskId { get; set; }[JsonProperty("task_status")]public string TaskStatus { get; set; }[JsonProperty("task_result")]public TTSQueryTaskResult TaskResult { get; set; }}[Serializable]public class TTSQueryTaskResult{[JsonProperty("speech_url")]public string SpeechUrl { get; set; }[JsonProperty("err_no")]public int ErrNo { get; set; }[JsonProperty("err_msg")]public string ErrMsg { get; set; }[JsonProperty("sn")]public string Sn { get; set; }}#endregion}

3、最終效果

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84941.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84941.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84941.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

銀河麒麟 | ubuntu 搭建屬于自己的郵件服務器

目錄 遇權不絕就轉root 更新系統 安裝 Postfix 配置 Postfix 重啟 Postfix 安裝 Dovecot 配置 Dovecot 編輯 Dovecot 的 IMAP 配置文件 編輯 Dovecot 的用戶認證配置文件 編輯 Dovecot 的服務配置文件 重啟 Dovecot 安裝發送郵箱功能 發送郵件 測試 遇權不絕就轉…

嵌入式通信協議框架的四層架構設計與實現

文章目錄 一、硬件抽象層&#xff1a;數據收發的基石1.1 設計要點1.2 代碼示例 二、協議管理層&#xff1a;智能路由中樞2.1 設計要點2.2 代碼示例 三、協議處理層&#xff1a;協議具體實現3.1 設計要求3.2代碼示例3.2.1 協議公共定義3.2.2 協議一設計3.2.3 協議二設計 四、應用…

RA信號處理

ra_snr_gui.m 作用&#xff1a;統計不同信噪比下&#xff0c;五種信號的峰值旁瓣比RA和低高頻均值比RM&#xff0c;繪制結果&#xff0c;參考圖3.11和3.12 DFCW_RA_SNR.m 作用&#xff1a;產生正交離散頻率編碼信號&#xff0c;并計算峰值旁瓣比RA和低高頻均值比 RM LFM_RA_S…

【go的測試】單測之gomock包與gomonkey包

目錄 使用gomock包 1. 安裝mockgen 2. 定義接口 3. 生成mock文件 4. 在單測中使用mock的函數 5. gomock 包的使用問題 使用gomonkey包 1. mock 一個包函數 2. mock 一個公有成員函數 3. mock 一個私有成員函數 使用gomock包 1. 安裝mockgen go get -u github.com/go…

html實現登錄與注冊功能案例(不寫死且只使用js)

目錄 案例需求 實現思路 代碼參考 login.html register.html 運行效果 升級思路 案例需求 需要一個登錄界面和注冊頁面實現一個較為完整的登錄注冊功能 1.登錄界面沒有登錄限制需求&#xff08;降低難度&#xff09;&#xff0c;實現基本的登錄判斷需求&#xff0c;彈窗…

PHP is the best language.

PHP很好寫。 眾所周知Python很好寫&#xff0c;Python 也能開發 Web 應用&#xff0c;但和 PHP 相比&#xff0c;在“直接處理網頁”這件事上&#xff0c;PHP 更加貼近底層和原生。 想快速搭建原型或者 B 端后臺工具&#xff0c;不妨用 PHP Laravel 來搞&#xff0c;真的很香…

Mybatis-Plus 在 getOne() 的時候要加上 .last(“limit 1“)

1.先寫結論: 1.為了確保 SQL 查詢只返回一條記錄&#xff08;當查詢返回多條時會報錯->多為代碼本身問題&#xff09;。 2.防止數據庫執行全表掃描 3.參考網址&#xff1a;問題記錄&#xff1a;MyBatis-Plus 中 ServiceImpl 類的 getOne_mybatis_無他&唯手熟爾-2048…

C語言:二分搜索函數

一、二分搜索基本概念 二分搜索&#xff08;Binary Search&#xff09;是一種在有序數組中查找特定元素的高效算法&#xff0c;時間復雜度為O(log n)。 基本特點&#xff1a; 僅適用于有序數組&#xff08;升序或降序&#xff09; 每次比較將搜索范圍減半 比線性搜索(O(n))…

[前端AI]LangChain.js 和 Next.js LLM構建——協助博客撰寫和總結助手

LangChain.js 和 Next.js LLM 后端應用于協助博客撰寫和總結領域是一個非常實用的方向&#xff01;這涉及到理解和處理文本內容&#xff0c;并生成新的、有結構的信息。 根據您之前提供的代碼和需求&#xff0c;我們可以在此基礎上進行更具針對性的功能規劃和技術實現。 博客…

用 GitHub Issues 做任務管理和任務 List,簡單好用!

說實話&#xff0c;我平時也是一個人寫代碼&#xff0c;每次開完會整理任務最麻煩&#xff1a; 一堆事項堆在聊天里、文檔里&#xff0c;或者散落在郵件里…… 為了理清這些&#xff0c;我通常會做一份 List&#xff0c;標好優先級&#xff0c;再安排到每日的工作里 雖然這個…

每日算法刷題Day35 6.22:leetcode枚舉技巧枚舉中間2道題,用時1h

枚舉中間 對于三個或者四個變量的問題&#xff0c;枚舉中間的變量往往更好算。 為什么&#xff1f;比如問題有三個下標&#xff0c;需要滿足 0≤i<j<k<n&#xff0c;對比一下&#xff1a; 枚舉 i&#xff0c;后續計算中還需保證 j<k。 枚舉 j&#xff0c;那么 i 和…

【教學類-18-06】20250623蒙德里安黑白七款合并WORD(500張、無學號)

背景需要 客戶買了蒙德里安黑白格子7種尺寸,但是不需要學號方塊,并指定要WORD 設計思路 【教學類-18-05】20241118正方形手工紙(蒙德里安-風格派-紅黃藍黑白)-CSDN博客文章瀏覽閱讀1.3k次,點贊29次,收藏18次。【教學類-18-05】20241118正方形手工紙(蒙德里安-風格派-紅…

langchain--(4)

7 Embedding文本向量化 Embedding文本向量化是一種將非結構化文本轉化為低維、連續數值向量的技術,旨在通過數學方式捕捉文本的語義、語法或特征信息,從而讓機器更高效地處理語言任務。其核心思想源于流形假設(Manifold Hypothesis),即認為高維原始數據(如文本)實際隱含…

DMDRS部署實施手冊(ORACLE=》DM)

DMDRS部署實施手冊&#xff08;ORACLE》DM&#xff09; 1 同步說明2 DMDRS安裝3 數據庫準備3.1 源端準備3.1.1 開啟歸檔日志和附加日志3.1.2 關閉回收站3.1.3 創建同步用戶 3.2 目標準備3.2.1 創建同步用戶 4 DMDRS配置4.1 源端配置4.2 目標配置 5 DMDRS啟動5.1 啟動源端服務5.…

十(1)作業:sqli-labs重點關卡

參考文章&#xff1a;詳細sqli-labs&#xff08;1-65&#xff09;通關講解-CSDN博客 第1關&#xff1a; 輸入 &#xff1a; ?id3 輸入 &#xff1a; ?id2 當輸入的數字不同&#xff0c;頁面的響應也不同&#xff0c;說明&#xff0c;輸入的內容被帶入到數據庫里查詢了 輸…

Python 爬蟲入門 Day 7 - 復盤 + 實戰挑戰日

Python 第二階段 - 爬蟲入門 &#x1f3af; 本周知識回顧 網絡請求與網頁結構基礎 HTML解析入門&#xff08;使用 BeautifulSoup&#xff09; 實現爬蟲多頁抓取與翻頁邏輯 模擬登錄爬蟲與 Session 維持 使用 XPath 進行網頁解析&#xff08;lxml XPath&#xff09; 反爬蟲應對…

WebRTC(七):媒體能力協商

目的 在 WebRTC 中&#xff0c;每個瀏覽器或終端支持的音視頻編解碼器、分辨率、碼率、幀率等可能不同。媒體能力協商的目的就是&#xff1a; 確保雙方能“聽得懂”對方發的媒體流&#xff1b;明確誰發送、誰接收、怎么發送&#xff1b;保障連接的互操作性和兼容性。 P2P的基…

可信啟動方案設計

安全之安全(security)博客目錄導讀 目錄 一、引言 二、關鍵數據(Critical Data) 三、度量槽(Measurement Slot) 四、可信啟動后端 1、事件日志(Event Log) 2、離散型 TPM(Discrete TPM) 3、RSE(運行時安全引擎) 五、平臺接口 平臺接口的職責: 1、函數:b…

?通義萬相2.1深度解析:AI視頻生成引擎FLF2V-14B全流程指南(命令行參數+模型架構+數據流)

&#x1f31f; 從零詳解&#xff1a;如何用AI模型生成視頻&#xff1f;命令行、模型結構、數據流全解析&#xff01; 本文通過一個實際案例&#xff0c;詳細解析使用AI模型生成視頻的整個流程。從命令行參數解讀到模型結構&#xff0c;再到數據在模型間的流動&#xff0c;一步步…

在 TypeScript 前端中使用 Umi-Request 調用 Java 接口的完整指南

下面我將詳細介紹如何在基于 TypeScript 的前端項目中使用 umi-request 調用 IntelliJ IDEA 中開發的 Java 接口&#xff0c;包括完整的實現方案和代碼示例。 整體方案設計 一、Java 后端接口準備 1. 創建 Spring Boot 控制器 // src/main/java/com/example/demo/controller…