using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public class RTChatSample : MonoBehaviour { /// /// 聊天配置 /// [SerializeField] private ChatSetting m_ChatSettings; #region UI定义 /// /// 聊天UI窗 /// [SerializeField] private GameObject m_ChatPanel; /// /// 输入的信息 /// [SerializeField] public InputField m_InputWord; /// /// 返回的信息 /// [SerializeField] private Text m_TextBack; /// /// 播放声音 /// [SerializeField] private AudioSource m_AudioSource; /// /// 发送信息按钮 /// [SerializeField] private Button m_CommitMsgBtn; #endregion #region 参数定义 /// /// 动画控制器 /// [SerializeField] private Animator m_Animator; /// /// 语音模式,设置为false,则不通过语音合成 /// [Header("设置是否通过语音合成播放文本")] [SerializeField] private bool m_IsVoiceMode = true; /// /// AI回复结束之后,回调 /// public Action OnAISpeakDone; #endregion private void Awake() { m_CommitMsgBtn.onClick.AddListener(delegate { SendData(); }); InputSettingWhenWebgl(); } #region 消息发送 /// /// webgl时处理,支持中文输入 /// private void InputSettingWhenWebgl() { #if UNITY_WEBGL m_InputWord.gameObject.AddComponent(); #endif } /// /// 发送信息 /// public void SendData() { if (m_InputWord.text.Equals("")) return; //添加记录聊天 m_ChatHistory.Add(m_InputWord.text); //提示词 string _msg = m_InputWord.text; //发送数据 m_ChatSettings.m_ChatModel.PostMsg(_msg, CallBack); m_InputWord.text = ""; m_TextBack.text = "正在思考中..."; //切换思考动作 SetAnimator("state", 1); } /// /// 带文字发送 /// /// public void SendData(string _postWord) { if (_postWord.Equals("")) return; //添加记录聊天 m_ChatHistory.Add(_postWord); //提示词 string _msg = _postWord; //发送数据 m_ChatSettings.m_ChatModel.PostMsg(_msg, CallBack); m_InputWord.text = ""; m_TextBack.text = "正在思考中..."; //切换思考动作 SetAnimator("state", 1); } /// /// AI回复的信息的回调 /// /// private void CallBack(string _response) { _response = _response.Trim(); m_TextBack.text = ""; Debug.Log("收到AI回复:" + _response); //记录聊天 m_ChatHistory.Add(_response); if (!m_IsVoiceMode || m_ChatSettings.m_TextToSpeech == null) { //开始逐个显示返回的文本 StartTypeWords(_response); return; } m_ChatSettings.m_TextToSpeech.Speak(_response, PlayVoice); } #endregion #region 语音输入 /// /// 语音识别返回的文本是否直接发送至LLM /// [SerializeField] private bool m_AutoSend = true; /// /// 语音提示 /// [SerializeField] private GameObject m_VoiceTipPanel; /// /// 录音的提示信息 /// [SerializeField] private Text m_RecordTips; /// /// 处理录制的音频数据 /// /// public void AcceptClip(AudioClip _audioClip) { if (m_ChatSettings.m_SpeechToText == null) return; m_RecordTips.text = "正在进行语音识别..."; m_ChatSettings.m_SpeechToText.SpeechToText(_audioClip, DealingTextCallback); } /// /// 处理识别到的文本 /// /// private void DealingTextCallback(string _msg) { m_RecordTips.text = _msg; StartCoroutine(SetTextVisible(m_RecordTips)); //自动发送 if (m_AutoSend) { SendData(_msg); return; } m_InputWord.text = _msg; } private IEnumerator SetTextVisible(Text _textbox) { yield return new WaitForSeconds(3f); _textbox.text = ""; } #endregion #region 语音合成 private void PlayVoice(AudioClip _clip, string _response) { m_AudioSource.clip = _clip; m_AudioSource.Play(); Debug.Log("音频时长:" + _clip.length); //开始逐个显示返回的文本 StartTypeWords(_response); //切换到说话动作 SetAnimator("state", 2); } #endregion #region 文字逐个显示 //逐字显示的时间间隔 [SerializeField] private float m_WordWaitTime = 0.2f; //是否显示完成 [SerializeField] private bool m_WriteState = false; /// /// 开始逐个打印 /// /// private void StartTypeWords(string _msg) { if (_msg == "") return; m_WriteState = true; StartCoroutine(SetTextPerWord(_msg)); } private IEnumerator SetTextPerWord(string _msg) { int currentPos = 0; while (m_WriteState) { yield return new WaitForSeconds(m_WordWaitTime); currentPos++; //更新显示的内容 m_TextBack.text = _msg.Substring(0, currentPos); m_WriteState = currentPos < _msg.Length; } //切换到等待动作 SetAnimator("state", 0); //回复结束 if (OnAISpeakDone != null) { OnAISpeakDone(); } } #endregion #region 聊天记录 //保存聊天记录 [SerializeField] private List m_ChatHistory; //缓存已创建的聊天气泡 [SerializeField] private List m_TempChatBox; //聊天记录显示层 [SerializeField] private GameObject m_HistoryPanel; //聊天文本放置的层 [SerializeField] private RectTransform m_rootTrans; //发送聊天气泡 [SerializeField] private ChatPrefab m_PostChatPrefab; //回复的聊天气泡 [SerializeField] private ChatPrefab m_RobotChatPrefab; //滚动条 [SerializeField] private ScrollRect m_ScroTectObject; //获取聊天记录 public void OpenAndGetHistory() { m_ChatPanel.SetActive(false); m_HistoryPanel.SetActive(true); ClearChatBox(); StartCoroutine(GetHistoryChatInfo()); } //返回 public void BackChatMode() { m_ChatPanel.SetActive(true); m_HistoryPanel.SetActive(false); } //清空已创建的对话框 private void ClearChatBox() { while (m_TempChatBox.Count != 0) { if (m_TempChatBox[0]) { Destroy(m_TempChatBox[0].gameObject); m_TempChatBox.RemoveAt(0); } } m_TempChatBox.Clear(); } //获取聊天记录列表 private IEnumerator GetHistoryChatInfo() { yield return new WaitForEndOfFrame(); for (int i = 0; i < m_ChatHistory.Count; i++) { if (i % 2 == 0) { ChatPrefab _sendChat = Instantiate(m_PostChatPrefab, m_rootTrans.transform); _sendChat.SetText(m_ChatHistory[i]); m_TempChatBox.Add(_sendChat.gameObject); continue; } ChatPrefab _reChat = Instantiate(m_RobotChatPrefab, m_rootTrans.transform); _reChat.SetText(m_ChatHistory[i]); m_TempChatBox.Add(_reChat.gameObject); } //重新计算容器尺寸 LayoutRebuilder.ForceRebuildLayoutImmediate(m_rootTrans); StartCoroutine(TurnToLastLine()); } private IEnumerator TurnToLastLine() { yield return new WaitForEndOfFrame(); //滚动到最近的消息 m_ScroTectObject.verticalNormalizedPosition = 0; } #endregion private void SetAnimator(string _para, int _value) { if (m_Animator == null) return; m_Animator.SetInteger(_para, _value); } }