2025-09-25 15:47:17 +08:00

454 lines
14 KiB
C#

using DG.Tweening;
using SuperScrollView.AI;
using System;
using System.Collections;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;
public class ChatUI : MonoBehaviour
{
public LoopListView2 mLoopListView;
/// <summary>
/// 发送信息按钮
/// </summary>
[SerializeField] private Button m_SendBtn;
/// <summary>
/// 输入的信息
/// </summary>
[SerializeField] public InputField m_InputWord;
[SerializeField] private Button hideDialogue;
[SerializeField] public Transform p1;
[SerializeField] public Transform p2;
[SerializeField] private GameObject chatuiObj;
[SerializeField] private AudioSource audioSource;
public AudioClip welcomeAudioCilp;
public Animator IP_Animator;
public static ChatUI Instance { get; private set; }
public GameObject prefab_h;
public GameObject prefab_v;
public GameObject prefab_h_next;
public GameObject prefab_v_next;
private float recordingSendCountdownTime = 1f;
private float recordingSendCurrentTime;
private float wakeUpCountdownTime = 5f;
private float wakeUpCurrentTime;
private Coroutine coroutine;
public XunFeiWakeup xunFeiWakeup;//语音唤醒
private bool chatUIOpen;
private string speakTxt;
public string SpeakTxt
{
get
{
return speakTxt;
}
set
{
recordingSendCurrentTime = recordingSendCountdownTime;
wakeUpCurrentTime = wakeUpCountdownTime;
speakTxt = value;
}
}
private bool thinking;
public bool Thinking
{
get { return thinking; }
set
{
if (value)
{
GenChatTxt("思考中...");
}
thinking = value;
}
}
//private bool typing;
//public bool Typing
//{
// get { return typing; }
// set
// {
// typing = value;
// }
//}
private bool closed;
Action action;
private void Awake()
{
Instance = this;
DontDestroyOnLoad(this);
hideDialogue.onClick.AddListener(HideDialogue);
xunFeiWakeup.callBack = Listener;
}
void Start()
{
mLoopListView.InitListView(ChatMsgDataSourceMgr.Get.TotalItemCount, OnGetItemByIndex);
m_SendBtn.onClick.AddListener(SendData);
#if UNITY_WEBGL
m_InputWord.gameObject.AddComponent<WebGLSupport.WebGLInput>();
#endif
}
#region
private void Update()
{
//回车发送
if (
(Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
&& !m_InputWord.text.Equals("")
&& m_SendBtn.interactable
&& gameObject.activeSelf
&& chatUIOpen
)
{
SendData();
}
//准备进入唤醒
if (wakeUpCurrentTime > 0 && !Thinking /*&& !Typing*/)
{
wakeUpCurrentTime -= Time.deltaTime;
}
//准备发送
if (recordingSendCurrentTime >= 0 && !Thinking /*&& !Typing*/)
{
recordingSendCurrentTime -= Time.deltaTime;
}
else
{
if (!string.IsNullOrEmpty(SpeakTxt))
{
Thinking = true;
OnAppendMsg(1, MsgTypeEnum.Str, SpeakTxt);
ChatAI.Instance.SendData(Regex.Replace(SpeakTxt, @"[\p{P}\p{S}]", ""), str =>
{
Thinking = false;
wakeUpCurrentTime = 0;
if (closed) return;
if (string.IsNullOrEmpty(str)) return;
if (str == "error")
{
GenChatTxt(str);
OnAppendMsg(0, MsgTypeEnum.Str, str);
}
else
{
//coroutine = StartCoroutine(TypeText(0.2f * str.Length, str, str => GenChatTxt(str), () => Typing = false));
GenChatTxt(str);
//Typing = false;
OnAppendMsg(0, MsgTypeEnum.Str, str);
//Typing = true;
ChatAI.Instance.PlayVoice(str, clip => {
audioSource.clip = clip;
audioSource.Play();
});
}
});
ChatAI.Instance.StopRecording();
SpeakTxt = "";
}
}
}
#endregion
public void SendAI(string str,Action action)
{
this.action = action;
CloseChatTxt();
if (!string.IsNullOrEmpty(str))
{
Thinking = true;
ChatAI.Instance.SendData(/*Regex.Replace(str, @"[\p{P}\p{S}]", "")*/str, str =>
{
Thinking = false;
wakeUpCurrentTime = 0;
if (string.IsNullOrEmpty(str)) return;
if (str == "error")
{
GenChatTxt(str);
OnAppendMsg(0, MsgTypeEnum.Str, str);
}
else
{
//coroutine = StartCoroutine(TypeText(0.18f * str.Length, str, str => GenChatTxt(str), () => Typing = false));
GenChatTxt(str);
//Typing = false;
OnAppendMsg(0, MsgTypeEnum.Str, str);
//Typing = true;
ChatAI.Instance.PlayVoice(str, clip => {
audioSource.clip = clip;
audioSource.Play();
});
}
});
ChatAI.Instance.StopRecording();
SpeakTxt = "";
}
}
public void SendAINext(string str, Action action)
{
this.action = action;
CloseChatTxt();
if (!string.IsNullOrEmpty(str))
{
Thinking = true;
ChatAI.Instance.SendData(/*Regex.Replace(str, @"[\p{P}\p{S}]", "")*/str, str =>
{
Thinking = false;
wakeUpCurrentTime = 0;
if (string.IsNullOrEmpty(str)) return;
if (str == "error")
{
GenChatTxtNext(str);
OnAppendMsg(0, MsgTypeEnum.Str, str);
}
else
{
//coroutine = StartCoroutine(TypeText(0.18f * str.Length, str, str => GenChatTxt(str), () => Typing = false));
GenChatTxtNext(str);
//Typing = false;
OnAppendMsg(0, MsgTypeEnum.Str, str);
//Typing = true;
ChatAI.Instance.PlayVoice(str, clip => {
audioSource.clip = clip;
audioSource.Play();
});
}
});
ChatAI.Instance.StopRecording();
SpeakTxt = "";
}
}
private void SendData()
{
//空字符退出
if (string.IsNullOrEmpty(m_InputWord.text)) return;
//提示词
OnAppendMsg(1, MsgTypeEnum.Str, m_InputWord.text);
//发送数据
ChatAI.Instance.SendData("用户消息:" + m_InputWord.text, ResponseCallBack);
//恢复
m_InputWord.text = "";
m_SendBtn.interactable = false;
}
/// <summary>
/// AI回复的信息的回调
/// </summary>
/// <param name="_response"></param>
private void ResponseCallBack(string _response)
{
_response = _response.Trim();
//VoiceBtnEnable();
m_SendBtn.interactable = true;
if (!string.IsNullOrEmpty(_response))
{
OnAppendMsg(0, MsgTypeEnum.Str, _response);
if(_response != "error")
{
ChatAI.Instance.PlayVoice(_response, clip => {
audioSource.clip = clip;
audioSource.Play();
});
}
}
}
LoopListViewItem2 OnGetItemByIndex(LoopListView2 listView, int index)
{
if (index < 0 || index >= ChatMsgDataSourceMgr.Get.TotalItemCount)
{
return null;
}
ChatMsg itemData = ChatMsgDataSourceMgr.Get.GetChatMsgByIndex(index);
if (itemData == null)
{
return null;
}
LoopListViewItem2 item = null;
if (itemData.mPersonId == 0)
{
if (System.Text.Encoding.UTF8.GetByteCount(itemData.mSrtMsg) >= 48)
{
item = listView.NewListViewItem("ItemPrefab1");
}
else
{
item = listView.NewListViewItem("ItemPrefab3");
}
}
else
{
if (System.Text.Encoding.UTF8.GetByteCount(itemData.mSrtMsg) >= 48)
{
item = listView.NewListViewItem("ItemPrefab2");
}
else
{
item = listView.NewListViewItem("ItemPrefab4");
}
}
ChatViewItem itemScript = item.GetComponent<ChatViewItem>();
if (item.IsInitHandlerCalled == false)
{
item.IsInitHandlerCalled = true;
itemScript.Init();
}
itemScript.SetItemData(itemData, index);
return item;
}
public void OnAppendMsg(int id, MsgTypeEnum msgTypeEnum, string msg)
{
ChatMsgDataSourceMgr.Get.AppendOneMsg(id, msgTypeEnum, msg);
mLoopListView.SetListItemCount(ChatMsgDataSourceMgr.Get.TotalItemCount, false);
mLoopListView.MovePanelToItemIndex(ChatMsgDataSourceMgr.Get.TotalItemCount - 1, 0);
}
public void HideDialogue()
{
ChatAI.Instance.StopVoice();
HideDialogueEvent();
IP_Animator.SetBool("out", false);
chatUIOpen = false;
}
public void ShowDialogue()
{
IP_Animator.SetBool("out",true);
chatUIOpen = true;
CloseChatTxtWithAction();
}
public void HideDialogueEvent()
{
chatuiObj.transform.DOMove(p2.position, 0.5f);
audioSource.Stop();
}
public void ShowDialogueEvent()
{
chatuiObj.transform.DOMove(p1.position, 0.5f);
//audioSource.volume = 1;
}
void Listener()
{
if (wakeUpCurrentTime <= 0 && !Thinking && /*!Typing*/ /*&& !audioSource.isPlaying &&*/ !chatUIOpen && !prefab_v_next.activeSelf && !prefab_h_next.activeSelf)
{
closed = false;
wakeUpCurrentTime = 0;
ChatAI.Instance.StopVoice();
audioSource.Stop();
if (coroutine != null) StopCoroutine(coroutine);
GenChatTxt("你好,我在");
//Typing = true;
audioSource.clip = welcomeAudioCilp;
audioSource.Play();
coroutine = StartCoroutine(WaitExecute(welcomeAudioCilp.length, () => {
wakeUpCurrentTime = wakeUpCountdownTime;
//Typing = false;
ChatAI.Instance.StartRecording(str => {
SpeakTxt = str;
});
}));
}
}
//void Check(string txt)
//{
// if (wakeUpCurrentTime <= 0 && Regex.Replace(txt, @"[\p{P}\p{S}]", "").Contains("小智小智") && !Thinking && !Typing && !audioSource.isPlaying && !chatUIOpen)
// {
// closed = false;
// wakeUpCurrentTime = 0;
// ChatAI.Instance.StopVoice();
// audioSource.Stop();
// if (coroutine != null) StopCoroutine(coroutine);
// GenChatTxt("你好,我在");
// Typing = true;
// audioSource.clip = welcomeAudioCilp;
// audioSource.Play();
// coroutine = StartCoroutine(WaitExecute(welcomeAudioCilp.length + 1.5f, () => {
// wakeUpCurrentTime = wakeUpCountdownTime;
// Typing = false;
// }));
// }
// if (!audioSource.isPlaying && wakeUpCurrentTime > 0 && !Thinking && !Typing && !closed && !chatUIOpen)
// {
// Debug.Log("语音正在输入中: " + Regex.Replace(txt, @"[\p{P}\p{S}]", ""));
// SpeakTxt = txt;
// }
//}
void GenChatTxt(string txt)
{
int lineCount = Regex.Matches(txt, @"\r\n|\r|\n").Count + 1;
if (System.Text.Encoding.UTF8.GetByteCount(txt) >= 48 || lineCount > 1)
{
prefab_v.gameObject.SetActive(true);
prefab_h.gameObject.SetActive(false);
prefab_v.GetComponentInChildren<ReplyItem>().SetItemData(txt);
}
else
{
prefab_v.gameObject.SetActive(false);
prefab_h.gameObject.SetActive(true);
prefab_h.GetComponentInChildren<ReplyItem>().SetItemData(txt);
}
}
void GenChatTxtNext(string txt)
{
prefab_h.gameObject.SetActive(false);
prefab_v.gameObject.SetActive(false);
int lineCount = Regex.Matches(txt, @"\r\n|\r|\n").Count + 1;
if (System.Text.Encoding.UTF8.GetByteCount(txt) >= 48 || lineCount > 1)
{
prefab_v_next.gameObject.SetActive(true);
prefab_h_next.gameObject.SetActive(false);
prefab_v_next.GetComponentInChildren<ReplyItem>().SetItemData(txt);
}
else
{
prefab_v_next.gameObject.SetActive(false);
prefab_h_next.gameObject.SetActive(true);
prefab_h_next.GetComponentInChildren<ReplyItem>().SetItemData(txt);
}
}
public void CloseChatTxt()
{
closed = true;
SpeakTxt = "";
wakeUpCurrentTime = 0;
ChatAI.Instance.StopRecording();
Thinking = false;
//Typing = false;
ChatAI.Instance.StopVoice();
ChatAI.Instance.StopSend();
audioSource.Stop();
prefab_h.gameObject.SetActive(false);
prefab_v.gameObject.SetActive(false);
prefab_h_next.gameObject.SetActive(false);
prefab_v_next.gameObject.SetActive(false);
if (coroutine != null) StopCoroutine(coroutine);
}
public void CloseChatTxtWithAction()
{
CloseChatTxt();
action?.Invoke();
}
IEnumerator WaitExecute(float t, Action callBack)
{
yield return new WaitForSeconds(t);
callBack?.Invoke();
}
//IEnumerator TypeText(float totalTime, string fullText, Action<string> callBack, Action action)
//{
// float timePerCharacter = totalTime / fullText.Length;
// for (int i = 0; i <= fullText.Length; i++)
// {
// callBack?.Invoke(fullText.Substring(0, i));
// yield return new WaitForSeconds(timePerCharacter);
// }
// action?.Invoke();
//}
}