Unity 接入阿里的全模態大模型Qwen2.5-Omni

1 參考

根據B站up主陰沉的怪咖? 開源的項目的基礎上修改接入

AI二次元老婆開源項目地址(unity-AI-Chat-Toolkit):

Github地址:https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit

Gitee地址:https://gitee.com/DammonSpace/unity-ai-chat-toolkit

2 官網參考

找到官網發現沒C#的案例,于是參考python的腳本,改為C#

阿里全模態的官方地址:阿里云百煉

3 語音輸入部分

在基類LLM里添加下屬代碼

  public virtual void PostMsgAudio(string base64Audio, Action<string> _callback, Action<bool> _endCallBack = null, Action<AudioClip> _AudioCallBack = null){//上下文條數設置CheckHistory();//提示詞處理string message = "當前為角色的人物設定:" + m_Prompt +" 回答的語言:" + lan;//緩存發送的信息列表Content content = new Content(){type = "input_audio",input_audio = new Input_audio(){data = string.Format("data:;base64,{0}", base64Audio),format = "mp3"}};Content content2 = new Content(){type = "text",text = message};Content[] contents = new Content[] { content, content2 };m_DataAudioList.Add(new SendDataAudio("user", contents));StartCoroutine(RequestAudio(message, _callback, _endCallBack, _AudioCallBack));}public virtual IEnumerator RequestAudio(string _postWord, System.Action<string> _callback, Action<bool> _endCallBack = null, Action<AudioClip> _AudioCallBack = null){yield return new WaitForEndOfFrame();}[Serializable]public class SendDataAudio{[SerializeField] public string role;[SerializeField] public Content[] content;public SendDataAudio() { }public SendDataAudio(string _role, Content[] _content){role = _role;content = _content;}}[Serializable]public class Content{[SerializeField] public string type;[SerializeField] public Input_audio input_audio;[SerializeField] public string text;}[Serializable]public class Input_audio{[SerializeField] public string data;[SerializeField] public string format;}

4 語音解析部分

新添加一個類AliQwenOmniChat,繼承LLM

using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using static ALiChat;public class AliQwenOmniChat : LLM
{public AliQwenOmniChat(){url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";}/// <summary>/// api key/// </summary>[SerializeField] private string api_key;/// <summary>/// AI設定/// </summary>public string m_SystemSetting = string.Empty;/// <summary>/// qwen-omni-turbo-0119/// </summary>public string m_gptModel = "qwen-omni-turbo-0119";[Header("設置說話的聲音")] public SpeekerRole per = SpeekerRole.Cherry;private void Start(){//運行時,添加AI設定m_DataList.Add(new SendData("system", m_SystemSetting));}/// <summary>/// 發送消息/// </summary>/// <returns></returns>public override void PostMsgAudio(string _msg, Action<string> _callback, Action<bool> endAction, Action<AudioClip> AudioAction){base.PostMsgAudio(_msg, _callback, endAction, AudioAction);}public override IEnumerator RequestAudio(string requestData, Action<string> callback, Action<bool> EndAction, Action<AudioClip> AudioAction){using (var request = new UnityWebRequest(url, "POST")){PostDataAudio _postData = new PostDataAudio{model = m_gptModel,stream = this.stream,messages = m_DataAudioList,temperature = 1,top_p = 0.7f,modalities = new string[] { "text", "audio" },audio = new Audio { voice = SetSpeeker(per), format = "wav" },stream_options = new Stream_options { include_usage = true },};string _jsonText = JsonUtility.ToJson(_postData).Trim();Debug.Log(_jsonText);byte[] data = System.Text.Encoding.UTF8.GetBytes(_jsonText);request.uploadHandler = (UploadHandler)new UploadHandlerRaw(data);request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();request.SetRequestHeader("Content-Type", "application/json");request.SetRequestHeader("Authorization", string.Format("Bearer {0}", api_key));yield return request.SendWebRequest();if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError){Debug.LogError("阿里Error: " + request.error);callback?.Invoke("阿里大模型出現點問題");yield break;}string temp = request.downloadHandler.text;var datas = temp.Split("data:");string textStr = "";string audioStr = "";foreach (var requestJson in datas){if (string.IsNullOrEmpty(requestJson))continue;Debug.Log(requestJson);var jsonP = JToken.Parse(requestJson);var item = jsonP["choices"][0];var audio = item["delta"].SelectToken("audio");if (audio != null){if (audio.SelectToken("transcript") != null){var tt = audio.SelectToken("transcript")?.ToString();//文字部分if (!string.IsNullOrEmpty(tt)){tt = tt.Trim();textStr += tt;}var finish = item.SelectToken("finish_reason");if (finish != null && finish.ToString() == "stop"){break;}}else{audioStr += audio.SelectToken("data")?.ToString();//語音部分}}}if (!string.IsNullOrEmpty(textStr)){callback.Invoke(textStr);}if (!string.IsNullOrEmpty(audioStr)){AudioAction(PlayAudio(audioStr));}EndAction.Invoke(true);}}//解析輸出的Base64 編碼的音頻數據AudioClip PlayAudio(string audioString){if (!string.IsNullOrEmpty(audioString)){byte[] audioBytes = Convert.FromBase64String(audioString);AudioClip audioClip = WavUtility.ConvertBytesToAudioClip(audioBytes, 24000);return audioClip;}return null;}//阿里提供的四種支持的音色private string SetSpeeker(SpeekerRole _role){if (_role == SpeekerRole.Cherry) return "Cherry";if (_role == SpeekerRole.Serena) return "Serena";if (_role == SpeekerRole.Ethan) return "Ethan";if (_role == SpeekerRole.Chelsie) return "Chelsie";return "Cherry";//默認為音色Cherry}#region 數據包[Serializable]public class PostDataAudio{[SerializeField] public string model;[SerializeField] public bool stream;[SerializeField] public List<SendDataAudio> messages;[SerializeField] public float temperature = 0.7f;[SerializeField] public float top_p;[SerializeField] public string[] modalities;[SerializeField] public Audio audio;[SerializeField] public Stream_options stream_options;}[Serializable]public class Audio{public string voice;public string format;}[Serializable]public class Stream_options{public bool include_usage;}#endregionpublic enum SpeekerRole{Cherry,Serena,Ethan,Chelsie}
}

5 測試

輸入需要語音輸入時,找到開源項目里的錄音結束處理的AcceptClip方法修改為:

  public bool AliQwenOmniChat = false;  private Queue<string> strDatas = new Queue<string>();private Queue<AudioClip> clipDatas = new Queue<AudioClip>();private bool end = true;private void AcceptClip(AudioClip _audioClip){if (m_ChatSettings.m_SpeechToText == null)return;if (AliQwenOmniChat)//阿里全模態語音輸入時{byte[] _audioData = WavUtility.FromAudioClip(_audioClip);string base64String = Convert.ToBase64String(_audioData);m_ChatSettings.m_ChatModel.PostMsgAudio(base64String, CallBack, EndCallBack, AudioCallBack);//阿里語音輸入m_InputWord.text = "阿里語音輸入完成";}else{m_ChatSettings.m_SpeechToText.SpeechToText(_audioClip, DealingTextCallback);}}private void EndCallBack(bool isCompate){Debug.Log("是否回到結束:" + isCompate);this.end = isCompate;}private void CallBack(string _response)//文字回調{_response = _response.Trim();//m_TextBack.text = "";//Debug.Log("收到AI回復:" + _response);if (GetMesssgeIndex == 0){m_TextBack2.text = "";//切換到說話動作Debug.Log("播放聲音******");m_TextBack.text = "";         SetAnimator("state", 2);}GetMesssgeIndex++;if (!string.IsNullOrEmpty(_response)){if (Ali)//阿里多模態直接返回語音  放到隊列里面          strDatas.Enqueue(_response);elsem_ChatSettings.m_TextToSpeech.Speak(_response, PlayAudio);}//添加聲音回調的方法private void AudioCallBack(AudioClip clip){clipDatas.Enqueue(clip);}private void Update(){if (AliQwenOmniChat){if (strDatas.Count > 0 && m_WriteState == false){StartTypeWords(strDatas.Dequeue());}if (clipDatas.Count > 0 && m_AudioSource.isPlaying == false){m_AudioSource.clip = clipDatas.Dequeue();m_AudioSource.Play();//返回的語音播放isEnd = false;}else if (m_AudioSource.isPlaying == false && this.end){if (isEnd){return;}isEnd = true;m_ChatHistory.Add(m_TextBack.text);m_AudioSource.Stop();resultDatas.Clear();GetMesssgeIndex = 0;切換到等待動作Debug.Log("切換到等待動作");             SetAnimator("state", 0);}}}

文字輸入和開源項目里的原先輸入一樣。

語音輸入測試:

我用聲音問:你叫什么名字?

輸入的打印:

語音輸入后,返回了文字和聲音,返回的打印:

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

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

相關文章

第十五屆藍橋杯 2024 C/C++組 合法密碼

目錄 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; 思路&#xff1a; substr函數&#xff1a; 思路詳解&#xff1a; 代碼&#xff1a; 代碼詳解; 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; P10906 [藍橋杯 2024 國 B] 合法密碼 -…

NoSQL 簡單講解

目錄 1. NoSQL 的背景與意義 1.1 數據庫的演變 1.2 NoSQL 的興起 2. NoSQL 數據庫的分類 2.1 鍵值存儲&#xff08;Key-Value Stores&#xff09; 2.2 文檔數據庫&#xff08;Document Stores&#xff09; 2.3 列族存儲&#xff08;Column-Family Stores&#xff09; 2.…

122.在 Vue3 中使用 OpenLayers 實現圖層層級控制(zIndex)顯示與設置詳解

?? 作者:彭麒 ?? 郵箱:1062470959@qq.com ?? 聲明:本文源碼歸吉檀迦俐所有,歡迎學習借鑒,如用于商業項目請注明出處 ?? ?? 技術棧:Vue 3 + Composition API + OpenLayers 6+ + Element Plus + Tailwind CSS ?? 一、什么是 zIndex(圖層層級)? 在地圖開發中…

車載測試用例開發-如何平衡用例覆蓋度和測試效率的方法論

1 摘要 在進行車載測試用例編寫時&#xff0c;會遇到多個條件導致用例排列組合爆炸的情況&#xff0c;但是為了產品測試質量&#xff0c;我們又不得不保證用例設計的需求覆蓋度&#xff0c;這樣又會使得測試周期非常長。我們如何平衡效率和測試質量&#xff1f;本文進行了一些…

AI——神經網絡以及TensorFlow使用

文章目錄 一、TensorFlow安裝二、張量、變量及其操作1、張量Tensor2、變量 三、tf.keras介紹1、使用tf.keras構建我們的模型2、激活函數1、sigmoid/logistics函數2、tanh函數3、RELU函數4、LeakReLu5、SoftMax6、如何選擇激活函數 3、參數初始化1、bias偏置初始化2、weight權重…

Kubernetes (k8s) 日常運維命令總結

一、資源查看 查看所有命名空間的 Pod kubectl get pod --all-namespaces查看指定命名空間的 Pod kubectl get pod --namespace <命名空間>查看所有部署&#xff08;Deployments&#xff09; kubectl get deployments.apps --all-namespaces查看所有守護進程集&#xff0…

【PostgreSQL教程】PostgreSQL 特別篇之 語言接口連接Perl

博主介紹:?全網粉絲22W+,CSDN博客專家、Java領域優質創作者,掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。 感興趣的可…

07-IDEA企業開發工具-開發入門程序

1. IDEA創建Java項目的代碼結構 項目結構: IDEA中的Java項目包含四種主要結構&#xff1a;工程(Project)、模塊(Module)、包(Package)、類(Class)。 工程(Project): 代表整個項目&#xff0c;通常是一個磁盤目錄或文件夾。模塊(Module): 工程下的子單元&#xff0c;用于劃分項…

深度解析云計算:概念、優勢與分類全覽

以下是對云計算概念、優點和分類更詳細的介紹&#xff1a; 一、云計算的概念 云計算是一種通過互聯網提供計算服務的模式&#xff0c;它基于虛擬化、分布式計算、網絡存儲等一系列先進技術&#xff0c;將計算資源進行整合和管理&#xff0c;形成一個龐大的資源池。這些資源包…

高并發系統的通用設計方法是什么?

背景 高并發系統的通用設計方法是解決系統在面對大量用戶訪問時的性能瓶頸問題。當系統遇到性能瓶頸時&#xff0c;通常是因為某個單點資源&#xff08;如數據庫、后端云服務器、網絡帶寬等&#xff09;達到了極限。 為了提升整個系統的容量&#xff0c;需要找到這個瓶頸資源…

【手機】vivo手機應用聲音分離方案

文章目錄 前言方案 前言 嘗試分離vivo手機音樂與其他應用的聲音 方案 最佳方案&#xff1a;網易云音樂設置內關閉音量均衡 上傳不同的白噪音&#xff0c;成功 goodlock&#xff0c;主要適用于三星手機&#xff0c;vivo不一定適用 app volume control &#xff0c;可行

一個報錯說函數為私有函數

你遇到的警告信息&#xff1a; warning: declaration of struct Zero2TenVDrv will not be visible outside of this function [-Wvisibility]這是編譯器提示你在某個函數內部聲明了一個結構體 struct Zero2TenVDrv&#xff0c;但這個結構體的聲明作用域僅限于該函數內部&…

3.2 Agent核心能力:感知、規劃、決策與執行

智能代理&#xff08;Agent&#xff09;是一種能夠在復雜環境中自主運作的計算實體&#xff0c;其智能行為依賴于四大核心能力&#xff1a;感知&#xff08;Perception&#xff09;、規劃&#xff08;Planning&#xff09;、決策&#xff08;Decision-making&#xff09;和執行…

圖解Mysql原理:深入理解事務的特性以及它的實現機制

前言 大家好&#xff0c;我是程序蛇玩編程。 Mysql中事務大家不陌生吧&#xff0c;事務就是要保證一組數據庫操作&#xff0c;要么全部成功&#xff0c;要么全部失敗。那它具有哪些特性&#xff0c;如何實現的呢?接著往下看。 正文 事務的特性: 事務的基本特性主要為四種…

進行網頁開發時,怎樣把function()中變量值在控制臺輸出,查看?

在網頁開發過程中&#xff0c;為了及時了解JavaScript中的function函數中的變量值&#xff0c;可以用控制臺命令console.log()把變量的值在控制臺輸出&#xff0c;方便調試時對函數變量值進行了解。 看下面的一段示例&#xff1a; <!DOCTYPE html> <html> &l…

linux內核進程管理(1)——創建,退出

linux源碼閱讀——進程管理&#xff08;1&#xff09; 1. 進程的基本介紹1.1 linux中進程和線程的區別1.2 task_struct中的基本內容1.3 命名空間ns(namespace)命名空間結構圖Linux 中的命名空間類型 1.4 進程標識符 2. 創建一個進程的流程2.1 CLONE宏2.2 創建進程系統調用1. do…

人像面部關鍵點檢測

此工作為本人近期做人臉情緒識別&#xff0c;CBAM模塊前是否能加人臉關鍵點檢測而做的嘗試。由于創新點不是在于檢測點的標注&#xff0c;而是CBAM的改進&#xff0c;因此&#xff0c;只是借用了現成庫Dilb與cv2進行。 首先&#xff0c;下載人臉關鍵點預測模型:Index of /file…

【Python】每隔一段時間自動清除網站上cookies的方法

我在寫爬蟲的時候&#xff0c;經常會因為點擊瀏覽太多的頁面&#xff0c;而導致很多的cookies累積。 雖然單個Cookie很小&#xff0c;但長期積累可能占用瀏覽器存儲空間&#xff0c;導致瀏覽器運行變慢&#xff08;尤其對老舊設備&#xff09;。 而且Cookies&#xff08;尤其…

非隔離電源芯片WT5104

非隔離電源芯片WT5104 非隔離電源芯片 WT5104 介紹 WT5104 是一款超高效且高精度的非隔離降壓開關電源恒壓控制驅動芯片&#xff0c;在各類電源轉換場景中提供5V輔助電源供電發揮著重要作用。 一、芯片特點 高集成度&#xff1a;內部集成 800V 功率 MOSFET&#xff0c;極大減…

基于 Python 的自然語言處理系列(83):InstructGPT 原理與實現

&#x1f4cc; 論文地址&#xff1a;Training language models to follow instructions with human feedback &#x1f4bb; 參考項目&#xff1a;instructGOOSE &#x1f4f7; 模型架構圖&#xff1a; 一、引言&#xff1a;為什么需要 InstructGPT&#xff1f; 傳統的語言模型…