Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/UX/UXChat.cs
2025-06-24 23:49:13 +08:00

233 lines
7.1 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Http;
using BITKit;
using BITKit.UX;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Net.BITKit;
using Net.BITKit.Chat;
using Net.Project.B.UX;
using Newtonsoft.Json;
using Project.B.Player;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using Object = System.Object;
namespace Net.Project.B.Chat
{
public class UXChat<TPanel> : UIToolkitSubPanel<TPanel>,IDisposable, IUXChat where TPanel : IUXPanel
{
private readonly IChatService _chatService;
private readonly IUXKeyMap<InputAction> _uxKeyMap;
private readonly ILogger<UXChat<TPanel>> _logger;
[UXBindPath("chat-field-container")]
private VisualElement _chatFieldContainer;
[UXBindPath("chat-container")]
private VisualElement _chatContainer;
[UXBindPath("chat-field")]
private TextField _chatField;
[UXBindPath("chat-scroll")]
private ScrollView _chatScroll;
[UXBindPath("voice-button")]
private Button _voiceButton;
private readonly ValidHandle _isEnabled = new();
private string _currentDevice;
private AudioClip _recordClip;
private UniTaskCompletionSource _waitVoice;
public UXChat(IServiceProvider serviceProvider, IChatService chatService, IUXKeyMap<InputAction> uxKeyMap, ILogger<UXChat<TPanel>> logger) : base(serviceProvider)
{
_chatService = chatService;
_uxKeyMap = uxKeyMap;
_logger = logger;
_chatService.OnMessageReceived += OnMessageReceived;
}
private async void OnVoice()
{
_chatField.SetEnabled(false);
_currentDevice = Microphone.devices[0];
_logger.LogInformation("开始录音");
_recordClip = Microphone.Start(_currentDevice, false, 10, 16000);
try
{
await _waitVoice.Task;
_logger.LogInformation("录音完成");
}
catch (OperationCanceledException)
{
_logger.LogInformation("录音取消");
return;
}
finally
{
Microphone.End(_currentDevice);
_waitVoice = null;
}
var newGo = new GameObject();
var audioSource =
newGo.AddComponent<AudioSource>();
audioSource.clip = _recordClip;
audioSource.Play();
var wav = AudioClipUtils.AudioClipToWavBytes(_recordClip);
await UniTask.Delay(TimeSpan.FromSeconds(_recordClip.length));
if (audioSource)
{
UnityEngine.Object.Destroy(newGo);
}
using var httpClient = new HttpClient();
var responseMessage = await httpClient.PostAsync(@"http://localhost:5062/api/vosk/gettext?modelName=vosk-model-en-us-0.42-gigaspeech", new ByteArrayContent(wav));
var message = await responseMessage.Content.ReadAsStringAsync();
_chatField.SetEnabled(true);
var data = JsonConvert.DeserializeObject<dynamic>(message);
Debug.Log(message);
_chatField.value = data.text;
}
protected override void OnInitiated()
{
base.OnInitiated();
_chatContainer.Clear();
if (Panel is UIToolKitPanel panel)
{
panel.InputActionGroup.RegisterCallback(_uxKeyMap.ChatKey, OnChat);
panel.OnExit+=()=>
{
_isEnabled.SetElements(this,false);
};
}
_isEnabled.AddListener(enabled =>
{
_chatFieldContainer.SetActive(enabled);
_voiceButton.SetActive(enabled);
if (enabled)
{
BITInputSystem.AllowInput.AddDisableElements(this);
BITAppForUnity.AllowCursor.AddElement(this);
_chatField.SetActive(true);
_chatField.focusable = true;
_chatField.schedule.Execute(_chatField.Focus).ExecuteLater(1);
_chatScroll.ScrollToBottom();
_chatScroll.focusable = true;
}
else
{
_waitVoice?.TrySetCanceled();
BITAppForUnity.AllowCursor.RemoveElement(this);
BITInputSystem.AllowInput.RemoveDisableElements(this);
_chatField.focusable = false;
_chatField.schedule.Execute(()=>
{
_chatScroll.ScrollToBottom();
_chatField.SetActive(false);
_chatField.SetValueWithoutNotify(string.Empty);
_chatField.Blur();
}).ExecuteLater(1);
_chatScroll.focusable = false;
}
_chatScroll.Blur();
});
_isEnabled.Invoke();
_chatField.RegisterCallback<KeyDownEvent>(OnKeyDown);
_chatField.BlinkingCursor();
_voiceButton.clicked += ToggleVoice;
}
private void ToggleVoice()
{
if (_waitVoice is not null)
{
_waitVoice.TrySetResult();
}
else
{
_waitVoice = new();
OnVoice();
}
}
private void OnKeyDown(KeyDownEvent keyDownEvent)
{
switch (keyDownEvent.keyCode)
{
case KeyCode.Return:
if (string.IsNullOrEmpty(_chatField.value) is false)
{
_chatService.SendMessage(new ChatMessage()
{
FromUserId = Environment.UserName,
ToUserId = "World",
Content = _chatField.value
});
_chatField.value = string.Empty;
keyDownEvent.StopPropagation();
keyDownEvent.PreventDefault();
}
break;
}
}
private void OnChat(InputAction.CallbackContext obj)
{
if (obj.JustPressed() is false)return;
_isEnabled.SetElements(this,!_isEnabled.Allow);
}
private void OnMessageReceived(ChatMessage obj)
{
var label = _chatContainer.Create<Label>();
label.text = $"<color=yellow>{obj.FromUserId}:</color>{obj.Content}";
_chatScroll.ScrollToBottomAutomatic();
}
public void Dispose()
{
}
}
}