Health/Assets/_VoiceAssistant/AIChatTookit/Scripts/Chat/RTChatSample.cs

348 lines
8.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class RTChatSample : MonoBehaviour
{
/// <summary>
/// 聊天配置
/// </summary>
[SerializeField] private ChatSetting m_ChatSettings;
#region UI定义
/// <summary>
/// 聊天UI窗
/// </summary>
[SerializeField] private GameObject m_ChatPanel;
/// <summary>
/// 输入的信息
/// </summary>
[SerializeField] public InputField m_InputWord;
/// <summary>
/// 返回的信息
/// </summary>
[SerializeField] private Text m_TextBack;
/// <summary>
/// 播放声音
/// </summary>
[SerializeField] private AudioSource m_AudioSource;
/// <summary>
/// 发送信息按钮
/// </summary>
[SerializeField] private Button m_CommitMsgBtn;
#endregion
#region
/// <summary>
/// 动画控制器
/// </summary>
[SerializeField] private Animator m_Animator;
/// <summary>
/// 语音模式设置为false,则不通过语音合成
/// </summary>
[Header("设置是否通过语音合成播放文本")]
[SerializeField] private bool m_IsVoiceMode = true;
/// <summary>
/// AI回复结束之后回调
/// </summary>
public Action OnAISpeakDone;
#endregion
private void Awake()
{
m_CommitMsgBtn.onClick.AddListener(delegate { SendData(); });
InputSettingWhenWebgl();
}
#region
/// <summary>
/// webgl时处理支持中文输入
/// </summary>
private void InputSettingWhenWebgl()
{
#if UNITY_WEBGL
m_InputWord.gameObject.AddComponent<WebGLSupport.WebGLInput>();
#endif
}
/// <summary>
/// 发送信息
/// </summary>
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);
}
/// <summary>
/// 带文字发送
/// </summary>
/// <param name="_postWord"></param>
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);
}
/// <summary>
/// AI回复的信息的回调
/// </summary>
/// <param name="_response"></param>
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
/// <summary>
/// 语音识别返回的文本是否直接发送至LLM
/// </summary>
[SerializeField] private bool m_AutoSend = true;
/// <summary>
/// 语音提示
/// </summary>
[SerializeField] private GameObject m_VoiceTipPanel;
/// <summary>
/// 录音的提示信息
/// </summary>
[SerializeField] private Text m_RecordTips;
/// <summary>
/// 处理录制的音频数据
/// </summary>
/// <param name="_data"></param>
public void AcceptClip(AudioClip _audioClip)
{
if (m_ChatSettings.m_SpeechToText == null)
return;
m_RecordTips.text = "正在进行语音识别...";
m_ChatSettings.m_SpeechToText.SpeechToText(_audioClip, DealingTextCallback);
}
/// <summary>
/// 处理识别到的文本
/// </summary>
/// <param name="_msg"></param>
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;
/// <summary>
/// 开始逐个打印
/// </summary>
/// <param name="_msg"></param>
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<string> m_ChatHistory;
//缓存已创建的聊天气泡
[SerializeField] private List<GameObject> 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);
}
}