380 lines
9.3 KiB
C#
380 lines
9.3 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.UI;
|
||
using WebGLSupport;
|
||
|
||
public class ChatSample : MonoBehaviour
|
||
{
|
||
/// <summary>
|
||
/// 聊天配置
|
||
/// </summary>
|
||
[SerializeField] private ChatSetting m_ChatSettings;
|
||
|
||
|
||
public VoiceWakeUp voiceWakeUp;
|
||
#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 CharacterAnimControlBase animControler;
|
||
/// <summary>
|
||
/// 语音模式,设置为false,则不通过语音合成
|
||
/// </summary>
|
||
[Header("设置是否通过语音合成播放文本")]
|
||
[SerializeField] private bool m_IsVoiceMode = true;
|
||
|
||
#endregion
|
||
|
||
private void Awake()
|
||
{
|
||
m_CommitMsgBtn.onClick.AddListener(delegate { SendData(); });
|
||
RegistButtonEvent();
|
||
InputSettingWhenWebgl();
|
||
m_VoiceInputs.onRecordOver += AcceptClip;
|
||
}
|
||
|
||
private IEnumerator Start()
|
||
{
|
||
while (!voiceWakeUp.IsEnable)
|
||
{
|
||
yield return null;
|
||
}
|
||
voiceWakeUp.StartRecgnition(OnRecgnizedKeyWord);
|
||
}
|
||
|
||
void OnRecgnizedKeyWord(bool successed)
|
||
{
|
||
if(successed)
|
||
{
|
||
StartRecord();
|
||
}
|
||
}
|
||
|
||
#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 = "正在思考中...";
|
||
|
||
//切换思考动作
|
||
animControler.Thinking();
|
||
}
|
||
/// <summary>
|
||
/// 带文字发送
|
||
/// </summary>
|
||
/// <param name="_postWord"></param>
|
||
public void SendData(string _postWord)
|
||
{
|
||
if (_postWord.Equals(""))
|
||
return;
|
||
|
||
//添加记录聊天
|
||
m_ChatHistory.Add(_postWord);
|
||
//提示词
|
||
string _msg = _postWord;
|
||
Debug.Log("玩家说:" + _postWord);
|
||
//发送数据
|
||
m_ChatSettings.m_ChatModel.PostMsg(_msg, CallBack);
|
||
|
||
m_InputWord.text = "";
|
||
m_TextBack.text = "正在思考中...";
|
||
|
||
//切换思考动作
|
||
animControler.Thinking();
|
||
}
|
||
|
||
/// <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;
|
||
[SerializeField] RecordVoiceUI recordVoiceUI;
|
||
/// <summary>
|
||
/// 语音输入处理类
|
||
/// </summary>
|
||
[SerializeField] private AudioRecorder m_VoiceInputs;
|
||
//[SerializeField] private VoiceInputs m_VoiceInputs;
|
||
/// <summary>
|
||
/// 注册按钮事件
|
||
/// </summary>
|
||
private void RegistButtonEvent()
|
||
{
|
||
recordVoiceUI.onStartListen += StartRecord;
|
||
recordVoiceUI.onStopListen += StopRecord;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始录制
|
||
/// </summary>
|
||
public void StartRecord()
|
||
{
|
||
animControler.SayHi();
|
||
m_VoiceInputs.StartRecordAudio();
|
||
}
|
||
/// <summary>
|
||
/// 结束录制
|
||
/// </summary>
|
||
public void StopRecord()
|
||
{
|
||
m_VoiceInputs.StopRecordAudio();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理录制的音频数据
|
||
/// </summary>
|
||
/// <param name="_data"></param>
|
||
private void AcceptData(byte[] _data)
|
||
{
|
||
if (m_ChatSettings.m_SpeechToText == null)
|
||
return;
|
||
|
||
m_ChatSettings.m_SpeechToText.SpeechToText(_data, DealingTextCallback);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理录制的音频数据
|
||
/// </summary>
|
||
/// <param name="_data"></param>
|
||
private void AcceptClip(AudioClip _audioClip,AudioRecorder.StopReason stopReason)
|
||
{
|
||
if (m_ChatSettings.m_SpeechToText == null)
|
||
return;
|
||
|
||
m_ChatSettings.m_SpeechToText.SpeechToText(_audioClip, DealingTextCallback);
|
||
}
|
||
/// <summary>
|
||
/// 处理识别到的文本
|
||
/// </summary>
|
||
/// <param name="_msg"></param>
|
||
private void DealingTextCallback(string _msg)
|
||
{
|
||
recordVoiceUI.SetRecordTips(_msg);
|
||
//自动发送
|
||
if (m_AutoSend)
|
||
{
|
||
SendData(_msg);
|
||
return;
|
||
}
|
||
|
||
m_InputWord.text = _msg;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 语音合成
|
||
|
||
private void PlayVoice(AudioClip _clip, string _response)
|
||
{
|
||
m_AudioSource.clip = _clip;
|
||
m_AudioSource.Play();
|
||
Debug.Log("音频时长:" + _clip.length);
|
||
//开始逐个显示返回的文本
|
||
StartTypeWords(_response);
|
||
//切换到说话动作
|
||
animControler.StartSpeek();
|
||
}
|
||
|
||
#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;
|
||
|
||
}
|
||
|
||
//切换到等待动作
|
||
animControler.Idle();
|
||
}
|
||
|
||
#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
|
||
|
||
}
|