Files
ApexSurgery/Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Requests/VoiceServiceRequest.cs
T
2025-07-04 20:33:06 +03:00

232 lines
8.2 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using Meta.Voice;
using Meta.WitAi.Configuration;
using Meta.WitAi.Json;
using UnityEngine;
namespace Meta.WitAi.Requests
{
[Serializable]
public abstract class VoiceServiceRequest
: NLPRequest<VoiceServiceRequestEvent, WitRequestOptions, VoiceServiceRequestEvents, VoiceServiceRequestResults>
{
/// <summary>
/// Constructor for Voice Service requests
/// </summary>
/// <param name="newInputType">The request input type (text/audio) to be used</param>
/// <param name="newOptions">The request parameters to be used</param>
/// <param name="newEvents">The request events to be called throughout it's lifecycle</param>
protected VoiceServiceRequest(NLPRequestInputType newInputType, WitRequestOptions newOptions, VoiceServiceRequestEvents newEvents) : base(newInputType, newOptions, newEvents) {}
/// <summary>
/// The status code returned from the last request
/// </summary>
public int StatusCode
{
get => Results == null ? 0 : Results.StatusCode;
protected set
{
int newCode = value;
if (newCode.Equals(Results == null ? 0 : Results.StatusCode))
{
return;
}
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.StatusCode = newCode;
}
}
#region Simulation
protected override bool OnSimulateResponse()
{
if (null == simulatedResponse) return false;
// Begin calling on main thread if needed
WatchMainThreadCallbacks();
SimulateResponse();
return true;
}
private async void SimulateResponse()
{
var stackTrace = new StackTrace();
StatusCode = simulatedResponse.code;
var statusDescription = simulatedResponse.responseDescription;
for (int i = 0; i < simulatedResponse.messages.Count - 1; i++)
{
var message = simulatedResponse.messages[i];
await System.Threading.Tasks.Task.Delay((int)(message.delay * 1000));
var partialResponse = WitResponseNode.Parse(message.responseBody);
HandlePartialNlpResponse(partialResponse);
}
var lastMessage = simulatedResponse.messages.Last();
await System.Threading.Tasks.Task.Delay((int)(lastMessage.delay * 1000));
var lastResponseData = WitResponseNode.Parse(lastMessage.responseBody);
MainThreadCallback(() =>
{
// Send partial data if not previously sent
if (!lastResponseData.HasResponse())
{
HandlePartialNlpResponse(lastResponseData);
}
// Apply error if needed
if (null != lastResponseData)
{
var error = lastResponseData["error"];
if (!string.IsNullOrEmpty(error))
{
statusDescription += $"\n{error}";
}
}
// Call completion delegate
HandleFinalNlpResponse(lastResponseData,
StatusCode == (int)HttpStatusCode.OK
? string.Empty
: $"{statusDescription}\n\nStackTrace:\n{stackTrace}\n\n");
});
}
#endregion
#region Thread Safety
// Check performing
private CoroutineUtility.CoroutinePerformer _performer = null;
// All actions
private ConcurrentQueue<Action> _mainThreadCallbacks = new ConcurrentQueue<Action>();
// While active, perform any sent callbacks
protected void WatchMainThreadCallbacks()
{
// Ignore if already performing
if (_performer != null)
{
return;
}
// Check callbacks every frame (editor or runtime)
_performer = CoroutineUtility.StartCoroutine(PerformMainThreadCallbacks());
}
// Every frame check for callbacks & perform any found
private System.Collections.IEnumerator PerformMainThreadCallbacks()
{
// While checking, continue
while (HasMainThreadCallbacks())
{
// Wait for frame
if (Application.isPlaying && !Application.isBatchMode)
{
yield return new WaitForEndOfFrame();
}
// Wait for a tick
else
{
yield return null;
}
// Perform if possible
while (_mainThreadCallbacks.Count > 0 && _mainThreadCallbacks.TryDequeue(out var result))
{
result();
}
}
_performer = null;
}
// If active or performing callbacks
private bool HasMainThreadCallbacks()
{
return IsActive || _mainThreadCallbacks.Count > 0;
}
// Called from background thread
protected void MainThreadCallback(Action action)
{
if (action == null)
{
return;
}
_mainThreadCallbacks.Enqueue(action);
}
#endregion
/// <summary>
/// Returns an empty result object with the current status code
/// </summary>
/// <param name="newMessage">The message to be set on the results</param>
protected override VoiceServiceRequestResults GetResultsWithMessage(string newMessage)
{
VoiceServiceRequestResults results = new VoiceServiceRequestResults(newMessage);
results.StatusCode = StatusCode;
results.ResponseData = ResponseData;
return results;
}
/// <summary>
/// Applies a transcription to the current results
/// </summary>
/// <param name="newTranscription">The transcription returned</param>
/// <param name="newIsFinal">Whether the transcription has completed building</param>
protected override void ApplyTranscription(string newTranscription, bool newIsFinal)
{
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.Transcription = newTranscription;
Results.IsFinalTranscription = newIsFinal;
if (Results.IsFinalTranscription)
{
List<string> transcriptions = new List<string>();
if (Results.FinalTranscriptions != null)
{
transcriptions.AddRange(Results.FinalTranscriptions);
}
transcriptions.Add(Results.Transcription);
Results.FinalTranscriptions = transcriptions.ToArray();
}
OnTranscriptionChanged();
}
/// <summary>
/// Applies response data to the current results
/// </summary>
/// <param name="newData">The returned response data</param>
protected override void ApplyResultResponseData(WitResponseNode newData)
{
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.ResponseData = newData;
}
/// <summary>
/// Performs an event callback with this request as the parameter
/// </summary>
/// <param name="eventCallback">The voice service request event to be called</param>
protected override void RaiseEvent(VoiceServiceRequestEvent eventCallback)
{
eventCallback?.Invoke(this);
}
}
}